@redacto.io/consent-sdk-react-native 5.0.0-beta.1 → 5.0.0-beta.10

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.mjs CHANGED
@@ -1,4 +1,7 @@
1
- import "./chunk-Y6FXYEAI.mjs";
1
+ import {
2
+ SANDBOX_TOKEN_HEADER,
3
+ toLanguageCode
4
+ } from "./chunk-B2TXWC2C.mjs";
2
5
 
3
6
  // src/RedactoNoticeConsent/RedactoNoticeConsent.tsx
4
7
  import {
@@ -27,6 +30,64 @@ import Svg3, { Path as Path3, Rect, SvgUri } from "react-native-svg";
27
30
  // src/RedactoNoticeConsent/api/index.ts
28
31
  import { jwtDecode } from "jwt-decode";
29
32
 
33
+ // src/RedactoNoticeConsent/api/sandbox.ts
34
+ var resolveSandboxAuth = (params) => {
35
+ var _a, _b, _c, _d, _e;
36
+ const token = (_a = params.token) == null ? void 0 : _a.trim();
37
+ if (!token) {
38
+ return null;
39
+ }
40
+ const organisationUuid = (_b = params.organisationUuid) == null ? void 0 : _b.trim();
41
+ const workspaceUuid = (_c = params.workspaceUuid) == null ? void 0 : _c.trim();
42
+ const ucic = (_d = params.sandboxUcic) == null ? void 0 : _d.trim();
43
+ const subject = (_e = params.sandboxSubject) == null ? void 0 : _e.trim();
44
+ if (!organisationUuid || !workspaceUuid) {
45
+ throw new Error(
46
+ "Sandbox mode requires organisationUuid and workspaceUuid props"
47
+ );
48
+ }
49
+ if (!ucic && !subject) {
50
+ throw new Error("Sandbox mode requires a UCIC, email, or mobile");
51
+ }
52
+ return { token, ucic, subject: subject != null ? subject : "", organisationUuid, workspaceUuid };
53
+ };
54
+ var resolveRequestAuth = (accessToken, sandboxParams, decodeTokenSafely2) => {
55
+ const sandbox = resolveSandboxAuth(sandboxParams);
56
+ if (sandbox) {
57
+ return {
58
+ organisationUuid: sandbox.organisationUuid,
59
+ workspaceUuid: sandbox.workspaceUuid,
60
+ sandbox
61
+ };
62
+ }
63
+ const decodedToken = accessToken ? decodeTokenSafely2(accessToken) : null;
64
+ if (!decodedToken) {
65
+ throw new Error("Invalid access token");
66
+ }
67
+ const { organisation_uuid, workspace_uuid } = decodedToken;
68
+ if (!organisation_uuid || !workspace_uuid) {
69
+ throw new Error("Invalid token: missing organization or workspace UUID");
70
+ }
71
+ return {
72
+ organisationUuid: organisation_uuid,
73
+ workspaceUuid: workspace_uuid,
74
+ sandbox: null
75
+ };
76
+ };
77
+ var buildAuthHeaders = (accessToken, sandbox) => {
78
+ if (sandbox) {
79
+ return { [SANDBOX_TOKEN_HEADER]: sandbox.token };
80
+ }
81
+ return { Authorization: `Bearer ${accessToken}` };
82
+ };
83
+ var sandboxBodyIdentity = (sandbox) => {
84
+ if (sandbox.ucic) {
85
+ return { org_user_id: sandbox.ucic };
86
+ }
87
+ return sandbox.subject.includes("@") ? { primary_email: sandbox.subject } : { primary_mobile: sandbox.subject };
88
+ };
89
+ var sandboxQueryIdentity = (sandbox) => sandboxBodyIdentity(sandbox);
90
+
30
91
  // src/constants.ts
31
92
  var DEFAULT_CONSENT_API_BASE_URL = "https://api.redacto.io/consent";
32
93
 
@@ -65,21 +126,19 @@ var fetchConsentContent = async ({
65
126
  specific_uuid,
66
127
  validate_against = "all",
67
128
  include_fully_consented_data = false,
68
- signal
129
+ signal,
130
+ ...sandboxParams
69
131
  }) => {
70
- if (!noticeId || !accessToken || !validate_against) {
71
- throw new Error("noticeId and accessToken are required");
72
- }
73
- const decodedToken = decodeTokenSafely(accessToken);
74
- if (!decodedToken) {
75
- throw new Error("Invalid access token");
132
+ if (!noticeId || !validate_against) {
133
+ throw new Error("noticeId is required");
76
134
  }
77
- const { organisation_uuid: ORGANISATION_UUID, workspace_uuid: WORKSPACE_UUID } = decodedToken;
78
- if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
79
- throw new Error("Invalid token: missing organization or workspace UUID");
135
+ if (!accessToken && !sandboxParams.token) {
136
+ throw new Error("accessToken or token is required");
80
137
  }
138
+ const { organisationUuid: ORGANISATION_UUID, workspaceUuid: WORKSPACE_UUID, sandbox } = resolveRequestAuth(accessToken, sandboxParams, decodeTokenSafely);
81
139
  const apiBaseUrl = baseUrl || DEFAULT_CONSENT_API_BASE_URL;
82
- const cacheKey = `${accessToken}-${noticeId}-${validate_against}-${language}-${specific_uuid || ""}-${include_fully_consented_data}`;
140
+ const cacheIdentity = sandbox ? `sandbox:${sandbox.organisationUuid}:${sandbox.workspaceUuid}:${sandbox.ucic || sandbox.subject}` : accessToken;
141
+ const cacheKey = `${cacheIdentity}-${noticeId}-${validate_against}-${language}-${specific_uuid || ""}-${include_fully_consented_data}`;
83
142
  if (validate_against === "all" && !specific_uuid) {
84
143
  const cachedData = getCachedData(cacheKey);
85
144
  if (cachedData) {
@@ -96,10 +155,15 @@ var fetchConsentContent = async ({
96
155
  if (include_fully_consented_data) {
97
156
  url.searchParams.append("include_fully_consented_data", "true");
98
157
  }
158
+ if (sandbox) {
159
+ for (const [key, value] of Object.entries(sandboxQueryIdentity(sandbox))) {
160
+ url.searchParams.append(key, value);
161
+ }
162
+ }
99
163
  const response = await fetch(url.toString(), {
100
164
  method: "GET",
101
165
  headers: {
102
- Authorization: `Bearer ${accessToken}`,
166
+ ...buildAuthHeaders(accessToken, sandbox),
103
167
  "Accept-Language": language,
104
168
  "Content-Type": "application/json"
105
169
  },
@@ -138,20 +202,18 @@ var submitConsentEvent = async ({
138
202
  meta_data,
139
203
  guardianVerificationReference,
140
204
  selfDeclaredAdult,
141
- signal
205
+ language,
206
+ signal,
207
+ ...sandboxParams
142
208
  }) => {
143
- if (!noticeUuid || !accessToken || !Array.isArray(purposes)) {
144
- throw new Error("noticeUuid, accessToken, and purposes array are required");
145
- }
146
- const decodedToken = decodeTokenSafely(accessToken);
147
- if (!decodedToken) {
148
- throw new Error("Invalid access token");
209
+ if (!noticeUuid || !Array.isArray(purposes)) {
210
+ throw new Error("noticeUuid and purposes array are required");
149
211
  }
150
- const { organisation_uuid: ORGANISATION_UUID, workspace_uuid: WORKSPACE_UUID } = decodedToken;
151
- if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
152
- throw new Error("Invalid token: missing organization or workspace UUID");
212
+ if (!accessToken && !sandboxParams.token) {
213
+ throw new Error("accessToken or token is required");
153
214
  }
154
- const apiBaseUrl = ledgerBaseUrl || baseUrl || DEFAULT_CONSENT_API_BASE_URL;
215
+ const { organisationUuid: ORGANISATION_UUID, workspaceUuid: WORKSPACE_UUID, sandbox } = resolveRequestAuth(accessToken, sandboxParams, decodeTokenSafely);
216
+ const apiBaseUrl = (sandbox ? null : ledgerBaseUrl) || baseUrl || DEFAULT_CONSENT_API_BASE_URL;
155
217
  const validatedPurposes = purposes.map((purpose) => {
156
218
  if (!purpose.uuid) {
157
219
  throw new Error("Invalid purpose data: missing uuid");
@@ -174,17 +236,19 @@ var submitConsentEvent = async ({
174
236
  declined: Boolean(declined),
175
237
  meta_data: meta_data ? { specific_uuid: meta_data.specific_uuid } : void 0,
176
238
  guardian_verification_reference: guardianVerificationReference,
177
- self_declared_adult: selfDeclaredAdult
239
+ self_declared_adult: selfDeclaredAdult,
240
+ language: toLanguageCode(language)
178
241
  };
242
+ const requestBody = sandbox ? { ...payload, ...sandboxBodyIdentity(sandbox) } : payload;
179
243
  const response = await fetch(
180
244
  `${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/submit-consent`,
181
245
  {
182
246
  method: "POST",
183
247
  headers: {
184
- Authorization: `Bearer ${accessToken}`,
248
+ ...buildAuthHeaders(accessToken, sandbox),
185
249
  "Content-Type": "application/json"
186
250
  },
187
- body: JSON.stringify(payload),
251
+ body: JSON.stringify(requestBody),
188
252
  signal
189
253
  }
190
254
  );
@@ -210,28 +274,30 @@ var submitConsentEvent = async ({
210
274
  var fetchTTSAudioUrls = async ({
211
275
  accessToken,
212
276
  baseUrl,
277
+ ledgerBaseUrl,
213
278
  noticeUuid,
214
279
  language,
215
- signal
280
+ signal,
281
+ ...sandboxParams
216
282
  }) => {
217
- if (!accessToken || !noticeUuid || !language) {
218
- throw new Error("accessToken, noticeUuid, and language are required");
219
- }
220
- const decodedToken = decodeTokenSafely(accessToken);
221
- if (!decodedToken) {
222
- throw new Error("Invalid access token");
223
- }
224
- const { organisation_uuid: ORGANISATION_UUID, workspace_uuid: WORKSPACE_UUID } = decodedToken;
225
- if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
226
- throw new Error("Invalid token: missing organization or workspace UUID");
283
+ if (!accessToken && !sandboxParams.token || !noticeUuid || !language) {
284
+ throw new Error("accessToken (or token), noticeUuid, and language are required");
227
285
  }
228
- const apiBaseUrl = baseUrl || DEFAULT_CONSENT_API_BASE_URL;
286
+ const { organisationUuid: ORGANISATION_UUID, workspaceUuid: WORKSPACE_UUID, sandbox } = resolveRequestAuth(accessToken, sandboxParams, decodeTokenSafely);
287
+ const apiBaseUrl = (sandbox ? null : ledgerBaseUrl) || baseUrl || DEFAULT_CONSENT_API_BASE_URL;
229
288
  const normalizedLanguage = language === "en" || language === "EN" ? "English" : language;
230
- const url = `${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/notices/${noticeUuid}/audio/${encodeURIComponent(normalizedLanguage)}`;
231
- const response = await fetch(url, {
289
+ const url = new URL(
290
+ `${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/notices/${noticeUuid}/audio/${encodeURIComponent(normalizedLanguage)}`
291
+ );
292
+ if (sandbox) {
293
+ for (const [key, value] of Object.entries(sandboxQueryIdentity(sandbox))) {
294
+ url.searchParams.append(key, value);
295
+ }
296
+ }
297
+ const response = await fetch(url.toString(), {
232
298
  method: "GET",
233
299
  headers: {
234
- Authorization: `Bearer ${accessToken}`,
300
+ ...buildAuthHeaders(accessToken, sandbox),
235
301
  Accept: "application/json",
236
302
  "Content-Type": "application/json"
237
303
  },
@@ -1745,6 +1811,12 @@ var RedactoNoticeConsent = ({
1745
1811
  noticeId,
1746
1812
  accessToken,
1747
1813
  refreshToken: _refreshToken,
1814
+ token,
1815
+ email,
1816
+ mobile,
1817
+ ucic,
1818
+ organisationUuid,
1819
+ workspaceUuid,
1748
1820
  baseUrl,
1749
1821
  ledgerBaseUrl,
1750
1822
  settings,
@@ -1760,6 +1832,16 @@ var RedactoNoticeConsent = ({
1760
1832
  }) => {
1761
1833
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u;
1762
1834
  const { isMobile } = useResponsive();
1835
+ const sandboxParams = useMemo(
1836
+ () => ({
1837
+ token,
1838
+ sandboxUcic: ucic,
1839
+ sandboxSubject: email || mobile,
1840
+ organisationUuid,
1841
+ workspaceUuid
1842
+ }),
1843
+ [token, ucic, email, mobile, organisationUuid, workspaceUuid]
1844
+ );
1763
1845
  const [content, setContent] = useState(null);
1764
1846
  const [isLoading, setIsLoading] = useState(true);
1765
1847
  const [isSubmitting, setIsSubmitting] = useState(false);
@@ -1814,20 +1896,22 @@ var RedactoNoticeConsent = ({
1814
1896
  setIsLoading(true);
1815
1897
  setErrorMessage(null);
1816
1898
  try {
1899
+ const noticeBaseUrl = ledgerBaseUrl && !applicationId && !token ? ledgerBaseUrl : baseUrl;
1817
1900
  const data = await fetchConsentContent({
1818
1901
  noticeId,
1819
1902
  accessToken,
1820
- baseUrl,
1903
+ baseUrl: noticeBaseUrl,
1821
1904
  language: "English",
1822
1905
  validate_against: validateAgainst,
1823
1906
  include_fully_consented_data: includeFullyConsentedData,
1824
1907
  specific_uuid: applicationId,
1825
- signal: abortControllerRef.current.signal
1908
+ signal: abortControllerRef.current.signal,
1909
+ ...sandboxParams
1826
1910
  });
1827
1911
  const activeConfig2 = data.detail.active_config;
1828
1912
  let purposeSelections = data.detail.purpose_selections;
1829
1913
  let reconsentRequired = data.detail.reconsent_required || false;
1830
- if (ledgerBaseUrl && !applicationId) {
1914
+ if (accessToken && ledgerBaseUrl && !applicationId && !token) {
1831
1915
  const ledgerStatus = await fetchNoticeConsentStatus({
1832
1916
  accessToken,
1833
1917
  ledgerBaseUrl,
@@ -1904,7 +1988,7 @@ var RedactoNoticeConsent = ({
1904
1988
  } finally {
1905
1989
  setIsLoading(false);
1906
1990
  }
1907
- }, [noticeId, accessToken, baseUrl, ledgerBaseUrl, validateAgainst, includeFullyConsentedData, applicationId, onAccept, onError]);
1991
+ }, [noticeId, accessToken, sandboxParams, token, baseUrl, ledgerBaseUrl, validateAgainst, includeFullyConsentedData, applicationId, onAccept, onError]);
1908
1992
  useEffect2(() => {
1909
1993
  hasBootstrappedLanguageRef.current = false;
1910
1994
  }, [noticeId, accessToken]);
@@ -1925,8 +2009,10 @@ var RedactoNoticeConsent = ({
1925
2009
  const data = await fetchTTSAudioUrls({
1926
2010
  accessToken,
1927
2011
  baseUrl,
2012
+ ledgerBaseUrl,
1928
2013
  noticeUuid: content.detail.active_config.notice_uuid,
1929
- language: selectedLanguage
2014
+ language: selectedLanguage,
2015
+ ...sandboxParams
1930
2016
  });
1931
2017
  const urls = {
1932
2018
  notice_text: data.detail.notice_text_audio_url,
@@ -1980,7 +2066,7 @@ var RedactoNoticeConsent = ({
1980
2066
  setTtsAudioUrls({});
1981
2067
  setIsTTSAvailable(false);
1982
2068
  }
1983
- }, [content, accessToken, baseUrl, selectedLanguage]);
2069
+ }, [content, accessToken, sandboxParams, baseUrl, ledgerBaseUrl, selectedLanguage]);
1984
2070
  const clearPlaybackWatchers = useCallback(() => {
1985
2071
  if (playbackSubscriptionRef.current) {
1986
2072
  playbackSubscriptionRef.current.remove();
@@ -2320,7 +2406,9 @@ var RedactoNoticeConsent = ({
2320
2406
  declined: false,
2321
2407
  meta_data: applicationId ? { specific_uuid: applicationId } : void 0,
2322
2408
  guardianVerificationReference: verificationReferenceRef.current || void 0,
2323
- selfDeclaredAdult: selfDeclaredAdult || void 0
2409
+ selfDeclaredAdult: selfDeclaredAdult || void 0,
2410
+ language: selectedLanguage,
2411
+ ...sandboxParams
2324
2412
  });
2325
2413
  await stopAudio();
2326
2414
  clearApiCache();
@@ -2335,7 +2423,7 @@ var RedactoNoticeConsent = ({
2335
2423
  } finally {
2336
2424
  setIsSubmitting(false);
2337
2425
  }
2338
- }, [content, accessToken, baseUrl, ledgerBaseUrl, applicationId, selectedPurposes, selectedDataElements, stopAudio, onAccept, onError]);
2426
+ }, [content, accessToken, sandboxParams, baseUrl, ledgerBaseUrl, applicationId, selectedPurposes, selectedDataElements, selectedLanguage, selfDeclaredAdult, stopAudio, onAccept, onError]);
2339
2427
  const handleDecline = useCallback(() => {
2340
2428
  stopAudio();
2341
2429
  stopPolling();
@@ -2950,14 +3038,16 @@ var fetchConsentContent2 = async ({
2950
3038
  org_uuid,
2951
3039
  workspace_uuid,
2952
3040
  notice_uuid,
3041
+ accessToken,
2953
3042
  baseUrl,
2954
3043
  language = "en",
2955
3044
  specific_uuid,
2956
3045
  signal
2957
3046
  }) => {
2958
3047
  const apiBaseUrl = baseUrl || DEFAULT_CONSENT_API_BASE_URL;
3048
+ const noticesUrl = `${apiBaseUrl}/public/organisations/${org_uuid}/workspaces/${workspace_uuid}/notices`;
2959
3049
  const url = new URL(
2960
- `${apiBaseUrl}/public/organisations/${org_uuid}/workspaces/${workspace_uuid}/notices/get-notice/${notice_uuid}`
3050
+ accessToken ? `${noticesUrl}/${notice_uuid}` : `${noticesUrl}/get-notice/${notice_uuid}`
2961
3051
  );
2962
3052
  if (specific_uuid) {
2963
3053
  url.searchParams.append("specific_uuid", specific_uuid);
@@ -2966,7 +3056,8 @@ var fetchConsentContent2 = async ({
2966
3056
  method: "GET",
2967
3057
  headers: {
2968
3058
  "Content-Type": "application/json",
2969
- "Accept-Language": language
3059
+ "Accept-Language": language,
3060
+ ...accessToken ? { Authorization: `Bearer ${accessToken}` } : {}
2970
3061
  },
2971
3062
  signal
2972
3063
  });
@@ -3000,7 +3091,8 @@ var submitConsentEvent2 = async ({
3000
3091
  noticeUuid,
3001
3092
  purposes,
3002
3093
  declined,
3003
- meta_data
3094
+ meta_data,
3095
+ language
3004
3096
  }) => {
3005
3097
  var _a, _b;
3006
3098
  const apiBaseUrl = ledgerBaseUrl || baseUrl || DEFAULT_CONSENT_API_BASE_URL;
@@ -3023,7 +3115,8 @@ var submitConsentEvent2 = async ({
3023
3115
  select_all_mandatory: false,
3024
3116
  source: "MOBILE",
3025
3117
  declined,
3026
- meta_data
3118
+ meta_data,
3119
+ language: toLanguageCode(language)
3027
3120
  };
3028
3121
  const response = await fetch(
3029
3122
  `${apiBaseUrl}/public/organisations/${org_uuid}/workspaces/${workspace_uuid}/submit-consent`,
@@ -3405,11 +3498,13 @@ var RedactoConsentInlineComponent = ({
3405
3498
  const fetchNotice = useCallback2(async (signal) => {
3406
3499
  setIsLoading(true);
3407
3500
  setFetchError(null);
3501
+ setHasAlreadyConsented(false);
3408
3502
  try {
3409
3503
  const consentContentData = await fetchConsentContent2({
3410
3504
  org_uuid,
3411
3505
  workspace_uuid,
3412
3506
  notice_uuid,
3507
+ accessToken,
3413
3508
  baseUrl,
3414
3509
  language,
3415
3510
  specific_uuid: applicationId,
@@ -3459,7 +3554,7 @@ var RedactoConsentInlineComponent = ({
3459
3554
  setIsLoading(false);
3460
3555
  }
3461
3556
  }
3462
- }, [org_uuid, workspace_uuid, notice_uuid, baseUrl, language, applicationId, onError]);
3557
+ }, [org_uuid, workspace_uuid, notice_uuid, accessToken, baseUrl, language, applicationId, onError]);
3463
3558
  useEffect3(() => {
3464
3559
  const controller = new AbortController();
3465
3560
  void fetchNotice(controller.signal);
@@ -3571,7 +3666,8 @@ var RedactoConsentInlineComponent = ({
3571
3666
  };
3572
3667
  }),
3573
3668
  declined: false,
3574
- meta_data: applicationId ? { specific_uuid: applicationId } : void 0
3669
+ meta_data: applicationId ? { specific_uuid: applicationId } : void 0,
3670
+ language: selectedLanguage
3575
3671
  });
3576
3672
  onAccept == null ? void 0 : onAccept();
3577
3673
  hasSubmittedRef.current = false;
@@ -3594,6 +3690,7 @@ var RedactoConsentInlineComponent = ({
3594
3690
  selectedDataElements,
3595
3691
  selectedPurposes,
3596
3692
  applicationId,
3693
+ selectedLanguage,
3597
3694
  onAccept
3598
3695
  ]
3599
3696
  );