@sendoracloud/sdk-react-native 0.18.2 → 0.18.4

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
@@ -1969,6 +1969,108 @@ var SendoraSDK = class {
1969
1969
  }
1970
1970
  };
1971
1971
  }
1972
+ /**
1973
+ * Consent namespace — GDPR/CCPA right-to-record + right-to-erasure
1974
+ * helpers. Mirrors backend `/consent/record` + `/consent/deletion-request`.
1975
+ *
1976
+ * Cookie banner / opt-in checkbox handler:
1977
+ * await SendoraCloud.consent.record({
1978
+ * purpose: "marketing",
1979
+ * granted: true,
1980
+ * email: currentUser.email,
1981
+ * source: "banner",
1982
+ * });
1983
+ *
1984
+ * "Delete my account" handler:
1985
+ * await SendoraCloud.consent.requestDeletion({
1986
+ * email: currentUser.email,
1987
+ * userId: currentUser.id,
1988
+ * reason: textarea.value,
1989
+ * });
1990
+ *
1991
+ * Backend enqueues a 7-day soft-delete; retention cron hard-deletes
1992
+ * after the grace window. Records are kept forever as legal evidence.
1993
+ */
1994
+ get consent() {
1995
+ const self = this;
1996
+ return {
1997
+ record: async (input) => {
1998
+ if (!self.config) throw new Error("[sendoracloud] init() must complete before consent.record().");
1999
+ const res = await post(
2000
+ { apiUrl: self.config.apiUrl, publicKey: self.config.publicKey, debug: self.debug },
2001
+ "/consent/record",
2002
+ input
2003
+ );
2004
+ if (!res || !res.ok) throw new Error(`[sendoracloud] consent.record failed (${res?.status ?? "network"})`);
2005
+ const parsed = await res.json();
2006
+ if (!parsed.success || !parsed.data) throw new Error("[sendoracloud] consent.record: bad response");
2007
+ return parsed.data;
2008
+ },
2009
+ requestDeletion: async (input) => {
2010
+ if (!self.config) throw new Error("[sendoracloud] init() must complete before consent.requestDeletion().");
2011
+ const res = await post(
2012
+ { apiUrl: self.config.apiUrl, publicKey: self.config.publicKey, debug: self.debug },
2013
+ "/consent/deletion-request",
2014
+ input
2015
+ );
2016
+ if (!res || !res.ok) throw new Error(`[sendoracloud] consent.requestDeletion failed (${res?.status ?? "network"})`);
2017
+ const parsed = await res.json();
2018
+ if (!parsed.success || !parsed.data) throw new Error("[sendoracloud] consent.requestDeletion: bad response");
2019
+ return parsed.data;
2020
+ }
2021
+ };
2022
+ }
2023
+ /**
2024
+ * Surveys namespace — fetch + submit NPS / CSAT / custom surveys
2025
+ * from inside the app. Mirrors backend `/surveys/:id/config` +
2026
+ * `/surveys/responses` SDK routes + the web SDK's
2027
+ * `sendora.surveys.showSurvey()` + `submitResponse()` shape.
2028
+ *
2029
+ * Typical use:
2030
+ * const survey = await SendoraCloud.surveys.fetchConfig("survey_nps_2026");
2031
+ * if (survey) {
2032
+ * // render survey.questions[] in your UI
2033
+ * await SendoraCloud.surveys.submitResponse({
2034
+ * surveyId: survey.id,
2035
+ * answers: { q1: 9, q2: "Loving it" },
2036
+ * completed: true,
2037
+ * });
2038
+ * }
2039
+ *
2040
+ * fetchConfig returns null when the survey is inactive / not found
2041
+ * (backend returns 404; SDK normalizes to null so callers can `if (!survey) return`).
2042
+ */
2043
+ get surveys() {
2044
+ const self = this;
2045
+ return {
2046
+ fetchConfig: async (surveyId) => {
2047
+ if (!self.config) throw new Error("[sendoracloud] init() must complete before surveys.fetchConfig().");
2048
+ if (typeof surveyId !== "string" || surveyId.length === 0) return null;
2049
+ const url = `${self.config.apiUrl}/api/v1/surveys/${encodeURIComponent(surveyId)}/config`;
2050
+ const res = await fetch(url, {
2051
+ method: "GET",
2052
+ headers: { "x-api-key": self.config.publicKey }
2053
+ });
2054
+ if (res.status === 404) return null;
2055
+ if (!res.ok) throw new Error(`[sendoracloud] surveys.fetchConfig failed (${res.status})`);
2056
+ const parsed = await res.json();
2057
+ if (!parsed.success || !parsed.data) return null;
2058
+ return parsed.data;
2059
+ },
2060
+ submitResponse: async (input) => {
2061
+ if (!self.config) throw new Error("[sendoracloud] init() must complete before surveys.submitResponse().");
2062
+ const res = await post(
2063
+ { apiUrl: self.config.apiUrl, publicKey: self.config.publicKey, debug: self.debug },
2064
+ "/surveys/responses",
2065
+ { completed: true, ...input }
2066
+ );
2067
+ if (!res || !res.ok) throw new Error(`[sendoracloud] surveys.submitResponse failed (${res?.status ?? "network"})`);
2068
+ const parsed = await res.json();
2069
+ if (!parsed.success || !parsed.data) throw new Error("[sendoracloud] surveys.submitResponse: bad response");
2070
+ return parsed.data;
2071
+ }
2072
+ };
2073
+ }
1972
2074
  /**
1973
2075
  * Clear identity + rotate the anonymous id. Call on logout. Awaits
1974
2076
  * the AsyncStorage writes so a caller who kills the app immediately
package/dist/index.d.cts CHANGED
@@ -880,6 +880,109 @@ declare class SendoraSDK {
880
880
  helpfulCount: number;
881
881
  }>>;
882
882
  };
883
+ /**
884
+ * Consent namespace — GDPR/CCPA right-to-record + right-to-erasure
885
+ * helpers. Mirrors backend `/consent/record` + `/consent/deletion-request`.
886
+ *
887
+ * Cookie banner / opt-in checkbox handler:
888
+ * await SendoraCloud.consent.record({
889
+ * purpose: "marketing",
890
+ * granted: true,
891
+ * email: currentUser.email,
892
+ * source: "banner",
893
+ * });
894
+ *
895
+ * "Delete my account" handler:
896
+ * await SendoraCloud.consent.requestDeletion({
897
+ * email: currentUser.email,
898
+ * userId: currentUser.id,
899
+ * reason: textarea.value,
900
+ * });
901
+ *
902
+ * Backend enqueues a 7-day soft-delete; retention cron hard-deletes
903
+ * after the grace window. Records are kept forever as legal evidence.
904
+ */
905
+ get consent(): {
906
+ record: (input: {
907
+ purpose: "marketing" | "analytics" | "functional" | "necessary";
908
+ granted: boolean;
909
+ entityId?: string;
910
+ userId?: string;
911
+ email?: string;
912
+ source?: string;
913
+ ipHash?: string;
914
+ }) => Promise<{
915
+ id: string;
916
+ purpose: string;
917
+ granted: boolean;
918
+ email: string | null;
919
+ userId: string | null;
920
+ source: string | null;
921
+ createdAt: string;
922
+ }>;
923
+ requestDeletion: (input: {
924
+ entityId?: string;
925
+ userId?: string;
926
+ email?: string;
927
+ reason?: string;
928
+ }) => Promise<{
929
+ id: string;
930
+ email: string | null;
931
+ userId: string | null;
932
+ status: string;
933
+ reason: string | null;
934
+ createdAt: string;
935
+ }>;
936
+ };
937
+ /**
938
+ * Surveys namespace — fetch + submit NPS / CSAT / custom surveys
939
+ * from inside the app. Mirrors backend `/surveys/:id/config` +
940
+ * `/surveys/responses` SDK routes + the web SDK's
941
+ * `sendora.surveys.showSurvey()` + `submitResponse()` shape.
942
+ *
943
+ * Typical use:
944
+ * const survey = await SendoraCloud.surveys.fetchConfig("survey_nps_2026");
945
+ * if (survey) {
946
+ * // render survey.questions[] in your UI
947
+ * await SendoraCloud.surveys.submitResponse({
948
+ * surveyId: survey.id,
949
+ * answers: { q1: 9, q2: "Loving it" },
950
+ * completed: true,
951
+ * });
952
+ * }
953
+ *
954
+ * fetchConfig returns null when the survey is inactive / not found
955
+ * (backend returns 404; SDK normalizes to null so callers can `if (!survey) return`).
956
+ */
957
+ get surveys(): {
958
+ fetchConfig: (surveyId: string) => Promise<{
959
+ id: string;
960
+ name: string;
961
+ questions: Array<{
962
+ id: string;
963
+ type: string;
964
+ label: string;
965
+ required?: boolean;
966
+ options?: string[];
967
+ scale?: {
968
+ min: number;
969
+ max: number;
970
+ };
971
+ }>;
972
+ [key: string]: unknown;
973
+ } | null>;
974
+ submitResponse: (input: {
975
+ surveyId: string;
976
+ answers: Record<string, unknown>;
977
+ completed?: boolean;
978
+ entityId?: string;
979
+ userId?: string;
980
+ metadata?: Record<string, unknown>;
981
+ }) => Promise<{
982
+ id: string;
983
+ submittedAt: string;
984
+ }>;
985
+ };
883
986
  /**
884
987
  * Clear identity + rotate the anonymous id. Call on logout. Awaits
885
988
  * the AsyncStorage writes so a caller who kills the app immediately
package/dist/index.d.ts CHANGED
@@ -880,6 +880,109 @@ declare class SendoraSDK {
880
880
  helpfulCount: number;
881
881
  }>>;
882
882
  };
883
+ /**
884
+ * Consent namespace — GDPR/CCPA right-to-record + right-to-erasure
885
+ * helpers. Mirrors backend `/consent/record` + `/consent/deletion-request`.
886
+ *
887
+ * Cookie banner / opt-in checkbox handler:
888
+ * await SendoraCloud.consent.record({
889
+ * purpose: "marketing",
890
+ * granted: true,
891
+ * email: currentUser.email,
892
+ * source: "banner",
893
+ * });
894
+ *
895
+ * "Delete my account" handler:
896
+ * await SendoraCloud.consent.requestDeletion({
897
+ * email: currentUser.email,
898
+ * userId: currentUser.id,
899
+ * reason: textarea.value,
900
+ * });
901
+ *
902
+ * Backend enqueues a 7-day soft-delete; retention cron hard-deletes
903
+ * after the grace window. Records are kept forever as legal evidence.
904
+ */
905
+ get consent(): {
906
+ record: (input: {
907
+ purpose: "marketing" | "analytics" | "functional" | "necessary";
908
+ granted: boolean;
909
+ entityId?: string;
910
+ userId?: string;
911
+ email?: string;
912
+ source?: string;
913
+ ipHash?: string;
914
+ }) => Promise<{
915
+ id: string;
916
+ purpose: string;
917
+ granted: boolean;
918
+ email: string | null;
919
+ userId: string | null;
920
+ source: string | null;
921
+ createdAt: string;
922
+ }>;
923
+ requestDeletion: (input: {
924
+ entityId?: string;
925
+ userId?: string;
926
+ email?: string;
927
+ reason?: string;
928
+ }) => Promise<{
929
+ id: string;
930
+ email: string | null;
931
+ userId: string | null;
932
+ status: string;
933
+ reason: string | null;
934
+ createdAt: string;
935
+ }>;
936
+ };
937
+ /**
938
+ * Surveys namespace — fetch + submit NPS / CSAT / custom surveys
939
+ * from inside the app. Mirrors backend `/surveys/:id/config` +
940
+ * `/surveys/responses` SDK routes + the web SDK's
941
+ * `sendora.surveys.showSurvey()` + `submitResponse()` shape.
942
+ *
943
+ * Typical use:
944
+ * const survey = await SendoraCloud.surveys.fetchConfig("survey_nps_2026");
945
+ * if (survey) {
946
+ * // render survey.questions[] in your UI
947
+ * await SendoraCloud.surveys.submitResponse({
948
+ * surveyId: survey.id,
949
+ * answers: { q1: 9, q2: "Loving it" },
950
+ * completed: true,
951
+ * });
952
+ * }
953
+ *
954
+ * fetchConfig returns null when the survey is inactive / not found
955
+ * (backend returns 404; SDK normalizes to null so callers can `if (!survey) return`).
956
+ */
957
+ get surveys(): {
958
+ fetchConfig: (surveyId: string) => Promise<{
959
+ id: string;
960
+ name: string;
961
+ questions: Array<{
962
+ id: string;
963
+ type: string;
964
+ label: string;
965
+ required?: boolean;
966
+ options?: string[];
967
+ scale?: {
968
+ min: number;
969
+ max: number;
970
+ };
971
+ }>;
972
+ [key: string]: unknown;
973
+ } | null>;
974
+ submitResponse: (input: {
975
+ surveyId: string;
976
+ answers: Record<string, unknown>;
977
+ completed?: boolean;
978
+ entityId?: string;
979
+ userId?: string;
980
+ metadata?: Record<string, unknown>;
981
+ }) => Promise<{
982
+ id: string;
983
+ submittedAt: string;
984
+ }>;
985
+ };
883
986
  /**
884
987
  * Clear identity + rotate the anonymous id. Call on logout. Awaits
885
988
  * the AsyncStorage writes so a caller who kills the app immediately
package/dist/index.js CHANGED
@@ -1931,6 +1931,108 @@ var SendoraSDK = class {
1931
1931
  }
1932
1932
  };
1933
1933
  }
1934
+ /**
1935
+ * Consent namespace — GDPR/CCPA right-to-record + right-to-erasure
1936
+ * helpers. Mirrors backend `/consent/record` + `/consent/deletion-request`.
1937
+ *
1938
+ * Cookie banner / opt-in checkbox handler:
1939
+ * await SendoraCloud.consent.record({
1940
+ * purpose: "marketing",
1941
+ * granted: true,
1942
+ * email: currentUser.email,
1943
+ * source: "banner",
1944
+ * });
1945
+ *
1946
+ * "Delete my account" handler:
1947
+ * await SendoraCloud.consent.requestDeletion({
1948
+ * email: currentUser.email,
1949
+ * userId: currentUser.id,
1950
+ * reason: textarea.value,
1951
+ * });
1952
+ *
1953
+ * Backend enqueues a 7-day soft-delete; retention cron hard-deletes
1954
+ * after the grace window. Records are kept forever as legal evidence.
1955
+ */
1956
+ get consent() {
1957
+ const self = this;
1958
+ return {
1959
+ record: async (input) => {
1960
+ if (!self.config) throw new Error("[sendoracloud] init() must complete before consent.record().");
1961
+ const res = await post(
1962
+ { apiUrl: self.config.apiUrl, publicKey: self.config.publicKey, debug: self.debug },
1963
+ "/consent/record",
1964
+ input
1965
+ );
1966
+ if (!res || !res.ok) throw new Error(`[sendoracloud] consent.record failed (${res?.status ?? "network"})`);
1967
+ const parsed = await res.json();
1968
+ if (!parsed.success || !parsed.data) throw new Error("[sendoracloud] consent.record: bad response");
1969
+ return parsed.data;
1970
+ },
1971
+ requestDeletion: async (input) => {
1972
+ if (!self.config) throw new Error("[sendoracloud] init() must complete before consent.requestDeletion().");
1973
+ const res = await post(
1974
+ { apiUrl: self.config.apiUrl, publicKey: self.config.publicKey, debug: self.debug },
1975
+ "/consent/deletion-request",
1976
+ input
1977
+ );
1978
+ if (!res || !res.ok) throw new Error(`[sendoracloud] consent.requestDeletion failed (${res?.status ?? "network"})`);
1979
+ const parsed = await res.json();
1980
+ if (!parsed.success || !parsed.data) throw new Error("[sendoracloud] consent.requestDeletion: bad response");
1981
+ return parsed.data;
1982
+ }
1983
+ };
1984
+ }
1985
+ /**
1986
+ * Surveys namespace — fetch + submit NPS / CSAT / custom surveys
1987
+ * from inside the app. Mirrors backend `/surveys/:id/config` +
1988
+ * `/surveys/responses` SDK routes + the web SDK's
1989
+ * `sendora.surveys.showSurvey()` + `submitResponse()` shape.
1990
+ *
1991
+ * Typical use:
1992
+ * const survey = await SendoraCloud.surveys.fetchConfig("survey_nps_2026");
1993
+ * if (survey) {
1994
+ * // render survey.questions[] in your UI
1995
+ * await SendoraCloud.surveys.submitResponse({
1996
+ * surveyId: survey.id,
1997
+ * answers: { q1: 9, q2: "Loving it" },
1998
+ * completed: true,
1999
+ * });
2000
+ * }
2001
+ *
2002
+ * fetchConfig returns null when the survey is inactive / not found
2003
+ * (backend returns 404; SDK normalizes to null so callers can `if (!survey) return`).
2004
+ */
2005
+ get surveys() {
2006
+ const self = this;
2007
+ return {
2008
+ fetchConfig: async (surveyId) => {
2009
+ if (!self.config) throw new Error("[sendoracloud] init() must complete before surveys.fetchConfig().");
2010
+ if (typeof surveyId !== "string" || surveyId.length === 0) return null;
2011
+ const url = `${self.config.apiUrl}/api/v1/surveys/${encodeURIComponent(surveyId)}/config`;
2012
+ const res = await fetch(url, {
2013
+ method: "GET",
2014
+ headers: { "x-api-key": self.config.publicKey }
2015
+ });
2016
+ if (res.status === 404) return null;
2017
+ if (!res.ok) throw new Error(`[sendoracloud] surveys.fetchConfig failed (${res.status})`);
2018
+ const parsed = await res.json();
2019
+ if (!parsed.success || !parsed.data) return null;
2020
+ return parsed.data;
2021
+ },
2022
+ submitResponse: async (input) => {
2023
+ if (!self.config) throw new Error("[sendoracloud] init() must complete before surveys.submitResponse().");
2024
+ const res = await post(
2025
+ { apiUrl: self.config.apiUrl, publicKey: self.config.publicKey, debug: self.debug },
2026
+ "/surveys/responses",
2027
+ { completed: true, ...input }
2028
+ );
2029
+ if (!res || !res.ok) throw new Error(`[sendoracloud] surveys.submitResponse failed (${res?.status ?? "network"})`);
2030
+ const parsed = await res.json();
2031
+ if (!parsed.success || !parsed.data) throw new Error("[sendoracloud] surveys.submitResponse: bad response");
2032
+ return parsed.data;
2033
+ }
2034
+ };
2035
+ }
1934
2036
  /**
1935
2037
  * Clear identity + rotate the anonymous id. Call on logout. Awaits
1936
2038
  * the AsyncStorage writes so a caller who kills the app immediately
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sendoracloud/sdk-react-native",
3
- "version": "0.18.2",
3
+ "version": "0.18.4",
4
4
  "description": "Sendora Cloud React Native + Expo SDK — analytics, identity, push-token registration, auth, deep links (Branch / Firebase Dynamic Links parity). Auth + analytics + deep links work in Expo Go; push token registration requires a Dev Client (EAS Build or `npx expo prebuild`).",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",