@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/dist/index.cjs CHANGED
@@ -28,6 +28,7 @@ __export(index_exports, {
28
28
  OrganizationSwitcher: () => OrganizationSwitcher,
29
29
  PasskeyEnrollment: () => PasskeyEnrollment,
30
30
  PasskeySignInButton: () => PasskeySignInButton,
31
+ PrivacyCenter: () => PrivacyCenter,
31
32
  SignIn: () => SignIn,
32
33
  SignUp: () => SignUp,
33
34
  SocialButtons: () => SocialButtons,
@@ -46,6 +47,7 @@ __export(index_exports, {
46
47
  useAuthOwlClient: () => useAuthOwlClient,
47
48
  useAuthOwlLocale: () => useAuthOwlLocale,
48
49
  useLocale: () => useLocale,
50
+ usePrivacy: () => usePrivacy,
49
51
  usePublicConfig: () => usePublicConfig,
50
52
  useServerError: () => useServerError,
51
53
  useSession: () => useSession,
@@ -212,6 +214,9 @@ function usePublicConfig() {
212
214
  isLoading: publicConfigState === "loading"
213
215
  };
214
216
  }
217
+ function usePrivacy() {
218
+ return useAuthOwlContext().client.privacy;
219
+ }
215
220
  function useSession() {
216
221
  const { client } = useAuthOwlContext();
217
222
  const store = client.sessionStore;
@@ -559,7 +564,7 @@ var import_native5 = require("@authowl/core/native");
559
564
  var import_jsx_runtime3 = require("react/jsx-runtime");
560
565
  function SignUp({ onSignedUp, structuredName = false, theme = defaultTheme }) {
561
566
  const t = useT();
562
- const { direction } = useLocale();
567
+ const { locale, direction } = useLocale();
563
568
  const toMessage = useServerError();
564
569
  const client = useAuthOwlClient();
565
570
  const config = usePublicConfig();
@@ -573,10 +578,18 @@ function SignUp({ onSignedUp, structuredName = false, theme = defaultTheme }) {
573
578
  const [busy, setBusy] = (0, import_react5.useState)(false);
574
579
  const [error, setError] = (0, import_react5.useState)(null);
575
580
  const [acceptedConsent, setAcceptedConsent] = (0, import_react5.useState)(false);
581
+ const [grantedPurposeCodes, setGrantedPurposeCodes] = (0, import_react5.useState)(
582
+ () => /* @__PURE__ */ new Set()
583
+ );
584
+ const [privacyCorrelationId] = (0, import_react5.useState)(import_native5.createIdempotencyKey);
576
585
  const legal = config.data?.legal;
586
+ const privacy = config.data?.privacy;
577
587
  (0, import_react5.useEffect)(() => {
578
588
  setAcceptedConsent(false);
579
589
  }, [legal?.version]);
590
+ (0, import_react5.useEffect)(() => {
591
+ setGrantedPurposeCodes(/* @__PURE__ */ new Set());
592
+ }, [privacy]);
580
593
  const useStructuredName = structuredName || capabilities.firstLastName;
581
594
  const displayName = useStructuredName ? [firstName.trim(), lastName.trim()].filter(Boolean).join(" ") : name.trim();
582
595
  const canSubmit = email.trim().length > 0 && password.length >= capabilities.passwordMinLength && password.length <= capabilities.passwordMaxLength && displayName.length > 0 && (!legal?.required || acceptedConsent);
@@ -589,6 +602,14 @@ function SignUp({ onSignedUp, structuredName = false, theme = defaultTheme }) {
589
602
  password,
590
603
  name: displayName,
591
604
  ...legal?.required ? { consentVersion: legal.version } : {},
605
+ ...privacy && privacy.notices.length > 0 ? {
606
+ privacyEvidence: (0, import_native5.buildPrivacySignUpEvidence)(
607
+ privacy,
608
+ locale,
609
+ grantedPurposeCodes,
610
+ privacyCorrelationId
611
+ )
612
+ } : {},
592
613
  ...useStructuredName ? { firstName: firstName.trim(), lastName: lastName.trim() } : {}
593
614
  });
594
615
  setBusy(false);
@@ -726,6 +747,25 @@ function SignUp({ onSignedUp, structuredName = false, theme = defaultTheme }) {
726
747
  consentSuffix
727
748
  ] })
728
749
  ] }) : null,
750
+ privacy && (privacy.notices.length > 0 || privacy.consentPurposes.length > 0) ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
751
+ NativePrivacySignUpEvidence,
752
+ {
753
+ privacy,
754
+ locale,
755
+ direction,
756
+ grantedPurposeCodes,
757
+ onPurposeChange: (purposeCode, granted) => {
758
+ setGrantedPurposeCodes((current) => {
759
+ const next = new Set(current);
760
+ if (granted) next.add(purposeCode);
761
+ else next.delete(purposeCode);
762
+ return next;
763
+ });
764
+ },
765
+ theme,
766
+ disabled: busy
767
+ }
768
+ ) : null,
729
769
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(FormError, { message: error, theme }),
730
770
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
731
771
  SubmitButton,
@@ -741,21 +781,338 @@ function SignUp({ onSignedUp, structuredName = false, theme = defaultTheme }) {
741
781
  )
742
782
  ] });
743
783
  }
784
+ function NativePrivacySignUpEvidence({
785
+ privacy,
786
+ locale,
787
+ direction,
788
+ grantedPurposeCodes,
789
+ onPurposeChange,
790
+ theme,
791
+ disabled
792
+ }) {
793
+ const t = useT();
794
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
795
+ import_react_native4.View,
796
+ {
797
+ style: {
798
+ gap: theme.spacing,
799
+ borderWidth: 1,
800
+ borderColor: theme.border,
801
+ borderRadius: theme.radius,
802
+ backgroundColor: theme.surface,
803
+ padding: theme.spacing
804
+ },
805
+ testID: "authowl-signup-privacy-evidence",
806
+ children: [
807
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: { gap: 4 }, children: [
808
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.Text, { style: { color: theme.text, fontSize: 16, fontWeight: "600" }, children: t("privacy.signup.title") }),
809
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.Text, { style: { color: theme.mutedText, fontSize: 13, lineHeight: 19 }, children: t("privacy.signup.description") })
810
+ ] }),
811
+ privacy.notices.map((notice) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
812
+ import_react_native4.View,
813
+ {
814
+ style: { gap: 4, borderTopWidth: 1, borderTopColor: theme.border, paddingTop: 10 },
815
+ children: [
816
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.Text, { style: { color: theme.text, fontSize: 14, fontWeight: "600", writingDirection: direction }, children: notice.title[locale] }),
817
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.Text, { style: { color: theme.mutedText, fontSize: 12, lineHeight: 18, writingDirection: direction }, children: notice.body[locale] })
818
+ ]
819
+ },
820
+ notice.noticeVersionId
821
+ )),
822
+ privacy.consentPurposes.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: { gap: 8 }, children: [
823
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.Text, { style: { color: theme.text, fontSize: 13, fontWeight: "600" }, children: t("privacy.signup.optional") }),
824
+ privacy.consentPurposes.map((purpose) => {
825
+ const granted = grantedPurposeCodes.has(purpose.code);
826
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
827
+ import_react_native4.Pressable,
828
+ {
829
+ testID: `authowl-signup-purpose-${purpose.code}`,
830
+ accessibilityRole: "checkbox",
831
+ accessibilityState: { checked: granted, disabled },
832
+ disabled,
833
+ onPress: () => onPurposeChange(purpose.code, !granted),
834
+ style: { flexDirection: "row", alignItems: "flex-start", gap: 8 },
835
+ children: [
836
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
837
+ import_react_native4.View,
838
+ {
839
+ style: {
840
+ width: 18,
841
+ height: 18,
842
+ alignItems: "center",
843
+ justifyContent: "center",
844
+ borderWidth: 1,
845
+ borderColor: granted ? theme.accent : theme.border,
846
+ borderRadius: 4,
847
+ backgroundColor: granted ? theme.accent : theme.background
848
+ },
849
+ children: granted ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.Text, { style: { color: theme.accentText, fontSize: 13 }, children: "\u2713" }) : null
850
+ }
851
+ ),
852
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: { flex: 1, gap: 2 }, children: [
853
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.Text, { style: { color: theme.text, fontSize: 13, fontWeight: "600", writingDirection: direction }, children: purpose.title[locale] }),
854
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.Text, { style: { color: theme.mutedText, fontSize: 12, lineHeight: 17, writingDirection: direction }, children: purpose.description[locale] })
855
+ ] })
856
+ ]
857
+ },
858
+ purpose.purposeVersionId
859
+ );
860
+ }),
861
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.Text, { style: { color: theme.mutedText, fontSize: 12, lineHeight: 18 }, children: t("privacy.signup.choiceNote") })
862
+ ] }) : null
863
+ ]
864
+ }
865
+ );
866
+ }
744
867
 
745
- // src/components/EmailOtpForm.tsx
868
+ // src/components/PrivacyCenter.tsx
746
869
  var import_react6 = require("react");
747
870
  var import_react_native5 = require("react-native");
748
871
  var import_jsx_runtime4 = require("react/jsx-runtime");
872
+ var RIGHT_KEYS = {
873
+ access: "privacy.right.access",
874
+ correction: "privacy.right.correction",
875
+ portability: "privacy.right.portability",
876
+ erasure: "privacy.right.erasure",
877
+ restriction: "privacy.right.restriction",
878
+ objection: "privacy.right.objection",
879
+ consent_withdrawal: "privacy.right.consentWithdrawal"
880
+ };
881
+ var STATE_KEYS = {
882
+ received: "privacy.state.received",
883
+ identity_pending: "privacy.state.identityPending",
884
+ in_progress: "privacy.state.inProgress",
885
+ restricted: "privacy.state.restricted",
886
+ completed: "privacy.state.completed",
887
+ denied: "privacy.state.denied",
888
+ withdrawn: "privacy.state.withdrawn"
889
+ };
890
+ function PrivacyCenter({ theme = defaultTheme } = {}) {
891
+ const t = useT();
892
+ const { locale, direction } = useLocale();
893
+ const toMessage = useServerError();
894
+ const client = useAuthOwlClient();
895
+ const config = usePublicConfig();
896
+ const session = useSession();
897
+ const [preferences, setPreferences] = (0, import_react6.useState)([]);
898
+ const [requests, setRequests] = (0, import_react6.useState)([]);
899
+ const [loading, setLoading] = (0, import_react6.useState)(true);
900
+ const [error, setError] = (0, import_react6.useState)(null);
901
+ const [pendingPurpose, setPendingPurpose] = (0, import_react6.useState)(null);
902
+ const [pendingRight, setPendingRight] = (0, import_react6.useState)(null);
903
+ const signedIn = session.data !== null;
904
+ const refresh = (0, import_react6.useCallback)(async (showLoading = false) => {
905
+ if (!signedIn) {
906
+ setLoading(false);
907
+ return;
908
+ }
909
+ if (showLoading) setLoading(true);
910
+ const [consent, rights] = await Promise.all([
911
+ client.privacy.listConsentPreferences(),
912
+ client.privacy.listRightsRequests()
913
+ ]);
914
+ const failure = consent.error ?? rights.error;
915
+ if (failure) setError(toMessage(failure, "privacy.error.load"));
916
+ else {
917
+ setPreferences(consent.data?.preferences ?? []);
918
+ setRequests(rights.data?.requests ?? []);
919
+ setError(null);
920
+ }
921
+ setLoading(false);
922
+ }, [client, signedIn, toMessage]);
923
+ (0, import_react6.useEffect)(() => {
924
+ if (!session.isPending) void refresh(true);
925
+ }, [refresh, session.data?.user.id, session.isPending]);
926
+ const preferencesByCode = (0, import_react6.useMemo)(
927
+ () => new Map(preferences.map((preference) => [preference.code, preference])),
928
+ [preferences]
929
+ );
930
+ async function updateConsent(purposeCode, granted) {
931
+ const privacy2 = config.data?.privacy;
932
+ const purpose = privacy2?.consentPurposes.find((item) => item.code === purposeCode);
933
+ const notice = privacy2?.notices.find((item) => item.purposeCodes.includes(purposeCode));
934
+ if (!purpose || !notice) {
935
+ setError(t("privacy.error.unavailable"));
936
+ return;
937
+ }
938
+ setPendingPurpose(purposeCode);
939
+ setError(null);
940
+ const result = await client.privacy.recordConsent({
941
+ purposeCode,
942
+ purposeVersionId: purpose.purposeVersionId,
943
+ noticeVersionId: notice.noticeVersionId,
944
+ decision: granted ? "granted" : "withdrawn",
945
+ locale
946
+ });
947
+ if (result.error) setError(toMessage(result.error, "privacy.error.save"));
948
+ else await refresh();
949
+ setPendingPurpose(null);
950
+ }
951
+ async function createRequest(rightType) {
952
+ setPendingRight(rightType);
953
+ setError(null);
954
+ const result = await client.privacy.createRightsRequest({ rightType, locale });
955
+ if (result.error) setError(toMessage(result.error, "privacy.error.request"));
956
+ else await refresh();
957
+ setPendingRight(null);
958
+ }
959
+ if (session.isPending || loading) {
960
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.ActivityIndicator, { color: theme.accent, testID: "authowl-privacy-loading" });
961
+ }
962
+ if (!signedIn) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.Text, { style: { color: theme.mutedText }, children: t("privacy.signedOut") });
963
+ const privacy = config.data?.privacy;
964
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
965
+ import_react_native5.View,
966
+ {
967
+ testID: "authowl-privacy-center",
968
+ style: { gap: theme.spacing, backgroundColor: theme.background },
969
+ children: [
970
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native5.View, { style: { gap: 4 }, children: [
971
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.Text, { style: { color: theme.mutedText, fontSize: 12, fontWeight: "700" }, children: t("privacy.dataUse") }),
972
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.Text, { style: { color: theme.text, fontSize: 22, fontWeight: "600" }, children: t("privacy.title") }),
973
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.Text, { style: { color: theme.mutedText, fontSize: 14, lineHeight: 20 }, children: t("privacy.description") })
974
+ ] }),
975
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(FormError, { message: error, theme, testID: "authowl-privacy-error" }),
976
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
977
+ PrivacyBlock,
978
+ {
979
+ title: t("privacy.choices.title"),
980
+ description: t("privacy.choices.description"),
981
+ theme,
982
+ children: (privacy?.consentPurposes.length ?? 0) === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.Text, { style: { color: theme.mutedText }, children: t("privacy.choices.empty") }) : privacy.consentPurposes.map((purpose) => {
983
+ const granted = preferencesByCode.get(purpose.code)?.state === "granted";
984
+ const pending = pendingPurpose === purpose.code;
985
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
986
+ import_react_native5.View,
987
+ {
988
+ style: { flexDirection: "row", alignItems: "center", gap: 10 },
989
+ children: [
990
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native5.View, { style: { flex: 1, gap: 2 }, children: [
991
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.Text, { style: { color: theme.text, fontWeight: "600", writingDirection: direction }, children: purpose.title[locale] }),
992
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.Text, { style: { color: theme.mutedText, fontSize: 12, lineHeight: 18, writingDirection: direction }, children: purpose.description[locale] })
993
+ ] }),
994
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
995
+ import_react_native5.Pressable,
996
+ {
997
+ testID: `authowl-privacy-purpose-${purpose.code}`,
998
+ accessibilityRole: "switch",
999
+ accessibilityLabel: purpose.title[locale],
1000
+ accessibilityState: { checked: granted, disabled: pending },
1001
+ disabled: pending,
1002
+ onPress: () => void updateConsent(purpose.code, !granted),
1003
+ style: {
1004
+ minWidth: 58,
1005
+ borderRadius: theme.radius,
1006
+ paddingHorizontal: 10,
1007
+ paddingVertical: 8,
1008
+ alignItems: "center",
1009
+ backgroundColor: granted ? theme.accent : theme.surface,
1010
+ borderWidth: 1,
1011
+ borderColor: granted ? theme.accent : theme.border,
1012
+ opacity: pending ? 0.55 : 1
1013
+ },
1014
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.Text, { style: { color: granted ? theme.accentText : theme.text, fontWeight: "600" }, children: pending ? t("common.working") : t(granted ? "privacy.on" : "privacy.off") })
1015
+ }
1016
+ )
1017
+ ]
1018
+ },
1019
+ purpose.purposeVersionId
1020
+ );
1021
+ })
1022
+ }
1023
+ ),
1024
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1025
+ PrivacyBlock,
1026
+ {
1027
+ title: t("privacy.rights.title"),
1028
+ description: t("privacy.rights.description"),
1029
+ theme,
1030
+ children: Object.keys(RIGHT_KEYS).map((right) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1031
+ import_react_native5.Pressable,
1032
+ {
1033
+ testID: `authowl-privacy-right-${right}`,
1034
+ accessibilityRole: "button",
1035
+ accessibilityState: { disabled: pendingRight !== null, busy: pendingRight === right },
1036
+ disabled: pendingRight !== null,
1037
+ onPress: () => void createRequest(right),
1038
+ style: {
1039
+ borderWidth: 1,
1040
+ borderColor: right === "erasure" ? theme.danger : theme.border,
1041
+ borderRadius: theme.radius,
1042
+ padding: 12,
1043
+ opacity: pendingRight !== null ? 0.55 : 1
1044
+ },
1045
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.Text, { style: { color: right === "erasure" ? theme.danger : theme.text, fontWeight: "600" }, children: pendingRight === right ? t("common.working") : t(RIGHT_KEYS[right]) })
1046
+ },
1047
+ right
1048
+ ))
1049
+ }
1050
+ ),
1051
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1052
+ PrivacyBlock,
1053
+ {
1054
+ title: t("privacy.requests.title"),
1055
+ description: t("privacy.requests.description"),
1056
+ theme,
1057
+ children: requests.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.Text, { style: { color: theme.mutedText }, children: t("privacy.requests.empty") }) : requests.map((request) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1058
+ import_react_native5.View,
1059
+ {
1060
+ style: { flexDirection: "row", justifyContent: "space-between", gap: 12 },
1061
+ children: [
1062
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.Text, { style: { flex: 1, color: theme.text }, children: t(RIGHT_KEYS[request.rightType]) }),
1063
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.Text, { style: { color: theme.mutedText, fontWeight: "600" }, children: t(STATE_KEYS[request.state]) })
1064
+ ]
1065
+ },
1066
+ request.id
1067
+ ))
1068
+ }
1069
+ )
1070
+ ]
1071
+ }
1072
+ );
1073
+ }
1074
+ function PrivacyBlock({
1075
+ title,
1076
+ description,
1077
+ theme,
1078
+ children
1079
+ }) {
1080
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1081
+ import_react_native5.View,
1082
+ {
1083
+ style: {
1084
+ gap: theme.spacing,
1085
+ borderWidth: 1,
1086
+ borderColor: theme.border,
1087
+ borderRadius: theme.radius,
1088
+ backgroundColor: theme.surface,
1089
+ padding: theme.spacing
1090
+ },
1091
+ children: [
1092
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native5.View, { style: { gap: 3 }, children: [
1093
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.Text, { style: { color: theme.text, fontSize: 16, fontWeight: "600" }, children: title }),
1094
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.Text, { style: { color: theme.mutedText, fontSize: 13, lineHeight: 19 }, children: description })
1095
+ ] }),
1096
+ children
1097
+ ]
1098
+ }
1099
+ );
1100
+ }
1101
+
1102
+ // src/components/EmailOtpForm.tsx
1103
+ var import_react7 = require("react");
1104
+ var import_react_native6 = require("react-native");
1105
+ var import_jsx_runtime5 = require("react/jsx-runtime");
749
1106
  function EmailOtpForm({ onSignedIn, theme = defaultTheme }) {
750
1107
  const t = useT();
751
1108
  const toMessage = useServerError();
752
1109
  const client = useAuthOwlClient();
753
1110
  const styles = useStyles(theme);
754
- const [stage, setStage] = (0, import_react6.useState)("email");
755
- const [email, setEmail] = (0, import_react6.useState)("");
756
- const [code, setCode] = (0, import_react6.useState)("");
757
- const [busy, setBusy] = (0, import_react6.useState)(false);
758
- const [error, setError] = (0, import_react6.useState)(null);
1111
+ const [stage, setStage] = (0, import_react7.useState)("email");
1112
+ const [email, setEmail] = (0, import_react7.useState)("");
1113
+ const [code, setCode] = (0, import_react7.useState)("");
1114
+ const [busy, setBusy] = (0, import_react7.useState)(false);
1115
+ const [error, setError] = (0, import_react7.useState)(null);
759
1116
  async function requestCode() {
760
1117
  if (busy || email.trim().length === 0) return;
761
1118
  setBusy(true);
@@ -789,8 +1146,8 @@ function EmailOtpForm({ onSignedIn, theme = defaultTheme }) {
789
1146
  setError(null);
790
1147
  }
791
1148
  if (stage === "email") {
792
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native5.View, { style: styles.container, testID: "authowl-emailotp", children: [
793
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1149
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native6.View, { style: styles.container, testID: "authowl-emailotp", children: [
1150
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
794
1151
  Field,
795
1152
  {
796
1153
  label: t("common.emailLabel"),
@@ -804,8 +1161,8 @@ function EmailOtpForm({ onSignedIn, theme = defaultTheme }) {
804
1161
  onSubmitEditing: requestCode
805
1162
  }
806
1163
  ),
807
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(FormError, { message: error, theme }),
808
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1164
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FormError, { message: error, theme }),
1165
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
809
1166
  SubmitButton,
810
1167
  {
811
1168
  label: t("emailOtp.requestSubmit"),
@@ -819,8 +1176,8 @@ function EmailOtpForm({ onSignedIn, theme = defaultTheme }) {
819
1176
  )
820
1177
  ] });
821
1178
  }
822
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native5.View, { style: styles.container, testID: "authowl-emailotp", children: [
823
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1179
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native6.View, { style: styles.container, testID: "authowl-emailotp", children: [
1180
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
824
1181
  Field,
825
1182
  {
826
1183
  label: t("emailOtp.codeLabel", { email: email.trim() }),
@@ -834,8 +1191,8 @@ function EmailOtpForm({ onSignedIn, theme = defaultTheme }) {
834
1191
  onSubmitEditing: verifyCode
835
1192
  }
836
1193
  ),
837
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(FormError, { message: error, theme }),
838
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1194
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FormError, { message: error, theme }),
1195
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
839
1196
  SubmitButton,
840
1197
  {
841
1198
  label: t("emailOtp.verifySubmit"),
@@ -847,14 +1204,14 @@ function EmailOtpForm({ onSignedIn, theme = defaultTheme }) {
847
1204
  testID: "authowl-emailotp-verify"
848
1205
  }
849
1206
  ),
850
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.Text, { style: styles.link, onPress: changeEmail, testID: "authowl-emailotp-change", children: t("emailOtp.changeEmail") })
1207
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native6.Text, { style: styles.link, onPress: changeEmail, testID: "authowl-emailotp-change", children: t("emailOtp.changeEmail") })
851
1208
  ] });
852
1209
  }
853
1210
 
854
1211
  // src/components/OrganizationSwitcher.tsx
855
- var import_react7 = require("react");
856
- var import_react_native6 = require("react-native");
857
- var import_jsx_runtime5 = require("react/jsx-runtime");
1212
+ var import_react8 = require("react");
1213
+ var import_react_native7 = require("react-native");
1214
+ var import_jsx_runtime6 = require("react/jsx-runtime");
858
1215
  function OrganizationSwitcher({
859
1216
  onSwitched,
860
1217
  allowPersonal = false,
@@ -866,14 +1223,14 @@ function OrganizationSwitcher({
866
1223
  const config = usePublicConfig();
867
1224
  const session = useSession();
868
1225
  const styles = useStyles(theme);
869
- const [organizations, setOrganizations] = (0, import_react7.useState)(null);
870
- const [switching, setSwitching] = (0, import_react7.useState)(null);
871
- const [error, setError] = (0, import_react7.useState)(null);
1226
+ const [organizations, setOrganizations] = (0, import_react8.useState)(null);
1227
+ const [switching, setSwitching] = (0, import_react8.useState)(null);
1228
+ const [error, setError] = (0, import_react8.useState)(null);
872
1229
  const activeId = session.data?.session.activeOrganizationId ?? null;
873
1230
  const userId = session.data?.user.id ?? null;
874
1231
  const signedIn = userId !== null;
875
- const requestGeneration = (0, import_react7.useRef)(0);
876
- const load = (0, import_react7.useCallback)(async () => {
1232
+ const requestGeneration = (0, import_react8.useRef)(0);
1233
+ const load = (0, import_react8.useCallback)(async () => {
877
1234
  const generation = ++requestGeneration.current;
878
1235
  setError(null);
879
1236
  const result = await client.organization.list();
@@ -884,7 +1241,7 @@ function OrganizationSwitcher({
884
1241
  }
885
1242
  setOrganizations(result.data ?? []);
886
1243
  }, [client, toMessage]);
887
- (0, import_react7.useEffect)(() => {
1244
+ (0, import_react8.useEffect)(() => {
888
1245
  requestGeneration.current += 1;
889
1246
  setOrganizations(null);
890
1247
  setError(null);
@@ -910,14 +1267,14 @@ function OrganizationSwitcher({
910
1267
  }
911
1268
  if (config.isLoading || config.data !== null && !config.data.organizations) return null;
912
1269
  if (!signedIn) {
913
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native6.View, { style: styles.container, testID: "authowl-orgswitcher", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native6.Text, { style: styles.label, children: t("organization.signedOut") }) });
1270
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native7.View, { style: styles.container, testID: "authowl-orgswitcher", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native7.Text, { style: styles.label, children: t("organization.signedOut") }) });
914
1271
  }
915
1272
  if (organizations === null && error === null) {
916
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native6.View, { style: styles.container, testID: "authowl-orgswitcher", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native6.Text, { style: styles.label, children: t("organization.loading") }) });
1273
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native7.View, { style: styles.container, testID: "authowl-orgswitcher", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native7.Text, { style: styles.label, children: t("organization.loading") }) });
917
1274
  }
918
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native6.View, { style: styles.container, testID: "authowl-orgswitcher", children: [
919
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native6.Text, { style: styles.label, children: t("organization.switcher.label") }),
920
- allowPersonal ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1275
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native7.View, { style: styles.container, testID: "authowl-orgswitcher", children: [
1276
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native7.Text, { style: styles.label, children: t("organization.switcher.label") }),
1277
+ allowPersonal ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
921
1278
  OrganizationRow,
922
1279
  {
923
1280
  label: t("organization.personal"),
@@ -929,7 +1286,7 @@ function OrganizationSwitcher({
929
1286
  theme
930
1287
  }
931
1288
  ) : null,
932
- (organizations ?? []).map((organization) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1289
+ (organizations ?? []).map((organization) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
933
1290
  OrganizationRow,
934
1291
  {
935
1292
  label: organization.name,
@@ -942,9 +1299,9 @@ function OrganizationSwitcher({
942
1299
  },
943
1300
  organization.id
944
1301
  )),
945
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FormError, { message: error, theme, testID: "authowl-orgswitcher-error" }),
946
- error !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
947
- import_react_native6.Text,
1302
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FormError, { message: error, theme, testID: "authowl-orgswitcher-error" }),
1303
+ error !== null ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1304
+ import_react_native7.Text,
948
1305
  {
949
1306
  style: styles.link,
950
1307
  onPress: () => void load(),
@@ -964,24 +1321,24 @@ function OrganizationRow({
964
1321
  theme
965
1322
  }) {
966
1323
  const styles = useStyles(theme);
967
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
968
- import_react_native6.Pressable,
1324
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1325
+ import_react_native7.Pressable,
969
1326
  {
970
1327
  onPress,
971
1328
  disabled: disabled || selected,
972
1329
  testID,
973
1330
  accessibilityRole: "button",
974
1331
  accessibilityState: { disabled: disabled || selected, busy },
975
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native6.Text, { style: selected ? [styles.label, { color: theme.accent }] : styles.label, children: label })
1332
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native7.Text, { style: selected ? [styles.label, { color: theme.accent }] : styles.label, children: label })
976
1333
  }
977
1334
  );
978
1335
  }
979
1336
 
980
1337
  // src/components/PasskeyEnrollment.tsx
981
- var import_react8 = require("react");
982
- var import_react_native7 = require("react-native");
1338
+ var import_react9 = require("react");
1339
+ var import_react_native8 = require("react-native");
983
1340
  var import_native6 = require("@authowl/core/native");
984
- var import_jsx_runtime6 = require("react/jsx-runtime");
1341
+ var import_jsx_runtime7 = require("react/jsx-runtime");
985
1342
  function usePasskeyClient() {
986
1343
  const client = useAuthOwlClient();
987
1344
  return "addPasskey" in client.passkey ? client : null;
@@ -998,8 +1355,8 @@ function PasskeyEnrollment({
998
1355
  const config = usePublicConfig();
999
1356
  const capabilities = (0, import_native6.resolveProjectCapabilities)(config.data);
1000
1357
  const styles = useStyles(theme);
1001
- const [busy, setBusy] = (0, import_react8.useState)(false);
1002
- const [error, setError] = (0, import_react8.useState)(null);
1358
+ const [busy, setBusy] = (0, import_react9.useState)(false);
1359
+ const [error, setError] = (0, import_react9.useState)(null);
1003
1360
  if (client === null || config.isLoading || config.data !== null && !capabilities.passkeyAdd) {
1004
1361
  return null;
1005
1362
  }
@@ -1015,11 +1372,11 @@ function PasskeyEnrollment({
1015
1372
  }
1016
1373
  onEnrolled?.();
1017
1374
  }
1018
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native7.View, { style: styles.container, testID: "authowl-passkey-enrollment", children: [
1019
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native7.Text, { style: styles.title, children: t("signUp.passkeyTitle") }),
1020
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native7.Text, { style: styles.label, children: t("signUp.passkeyDescription") }),
1021
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FormError, { message: error, theme, testID: "authowl-passkey-error" }),
1022
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1375
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: styles.container, testID: "authowl-passkey-enrollment", children: [
1376
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native8.Text, { style: styles.title, children: t("signUp.passkeyTitle") }),
1377
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native8.Text, { style: styles.label, children: t("signUp.passkeyDescription") }),
1378
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(FormError, { message: error, theme, testID: "authowl-passkey-error" }),
1379
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1023
1380
  SubmitButton,
1024
1381
  {
1025
1382
  label: t("signUp.passkeySubmit"),
@@ -1030,7 +1387,7 @@ function PasskeyEnrollment({
1030
1387
  testID: "authowl-passkey-submit"
1031
1388
  }
1032
1389
  ),
1033
- onSkip ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native7.Text, { style: styles.link, onPress: onSkip, testID: "authowl-passkey-skip", children: t("signUp.passkeySkip") }) : null
1390
+ onSkip ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native8.Text, { style: styles.link, onPress: onSkip, testID: "authowl-passkey-skip", children: t("signUp.passkeySkip") }) : null
1034
1391
  ] });
1035
1392
  }
1036
1393
  function PasskeySignInButton({
@@ -1043,8 +1400,8 @@ function PasskeySignInButton({
1043
1400
  const config = usePublicConfig();
1044
1401
  const capabilities = (0, import_native6.resolveProjectCapabilities)(config.data);
1045
1402
  const styles = useStyles(theme);
1046
- const [busy, setBusy] = (0, import_react8.useState)(false);
1047
- const [error, setError] = (0, import_react8.useState)(null);
1403
+ const [busy, setBusy] = (0, import_react9.useState)(false);
1404
+ const [error, setError] = (0, import_react9.useState)(null);
1048
1405
  if (client === null || config.isLoading || config.data !== null && !capabilities.passkeySignIn) return null;
1049
1406
  async function signIn() {
1050
1407
  if (busy || client === null) return;
@@ -1058,8 +1415,8 @@ function PasskeySignInButton({
1058
1415
  }
1059
1416
  onSignedIn?.();
1060
1417
  }
1061
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native7.View, { style: styles.container, testID: "authowl-passkey-signin", children: [
1062
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1418
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: styles.container, testID: "authowl-passkey-signin", children: [
1419
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1063
1420
  SubmitButton,
1064
1421
  {
1065
1422
  label: t("passkey.signInButton"),
@@ -1070,7 +1427,7 @@ function PasskeySignInButton({
1070
1427
  testID: "authowl-passkey-signin-submit"
1071
1428
  }
1072
1429
  ),
1073
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FormError, { message: error, theme, testID: "authowl-passkey-signin-error" })
1430
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(FormError, { message: error, theme, testID: "authowl-passkey-signin-error" })
1074
1431
  ] });
1075
1432
  }
1076
1433
 
@@ -1085,9 +1442,9 @@ function createNativePasskeys(adapter) {
1085
1442
  }
1086
1443
 
1087
1444
  // src/components/SocialButtons.tsx
1088
- var import_react9 = require("react");
1089
- var import_react_native8 = require("react-native");
1090
- var import_jsx_runtime7 = require("react/jsx-runtime");
1445
+ var import_react10 = require("react");
1446
+ var import_react_native9 = require("react-native");
1447
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1091
1448
  function SocialButtons({
1092
1449
  providers,
1093
1450
  onSignedIn,
@@ -1097,8 +1454,8 @@ function SocialButtons({
1097
1454
  const toMessage = useServerError();
1098
1455
  const client = useAuthOwlClient();
1099
1456
  const styles = useStyles(theme);
1100
- const [pending, setPending] = (0, import_react9.useState)(null);
1101
- const [error, setError] = (0, import_react9.useState)(null);
1457
+ const [pending, setPending] = (0, import_react10.useState)(null);
1458
+ const [error, setError] = (0, import_react10.useState)(null);
1102
1459
  async function signIn(provider) {
1103
1460
  if (pending !== null) return;
1104
1461
  setPending(provider.id);
@@ -1119,8 +1476,8 @@ function SocialButtons({
1119
1476
  }
1120
1477
  }
1121
1478
  if (providers.length === 0) return null;
1122
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: styles.container, testID: "authowl-social", children: [
1123
- providers.map((provider) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1479
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles.container, testID: "authowl-social", children: [
1480
+ providers.map((provider) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1124
1481
  SubmitButton,
1125
1482
  {
1126
1483
  label: t("social.continueWith", { provider: provider.label }),
@@ -1135,7 +1492,7 @@ function SocialButtons({
1135
1492
  },
1136
1493
  provider.id
1137
1494
  )),
1138
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(FormError, { message: error, theme, testID: "authowl-social-error" })
1495
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(FormError, { message: error, theme, testID: "authowl-social-error" })
1139
1496
  ] });
1140
1497
  }
1141
1498
 
@@ -1165,6 +1522,7 @@ var import_native8 = require("@authowl/core/native");
1165
1522
  OrganizationSwitcher,
1166
1523
  PasskeyEnrollment,
1167
1524
  PasskeySignInButton,
1525
+ PrivacyCenter,
1168
1526
  SignIn,
1169
1527
  SignUp,
1170
1528
  SocialButtons,
@@ -1183,6 +1541,7 @@ var import_native8 = require("@authowl/core/native");
1183
1541
  useAuthOwlClient,
1184
1542
  useAuthOwlLocale,
1185
1543
  useLocale,
1544
+ usePrivacy,
1186
1545
  usePublicConfig,
1187
1546
  useServerError,
1188
1547
  useSession,