@redacto.io/consent-sdk-react-native 5.0.0-beta.6 → 5.0.0-beta.7

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,6 +1,7 @@
1
1
  import {
2
+ SANDBOX_TOKEN_HEADER,
2
3
  toLanguageCode
3
- } from "./chunk-UVRSRLYW.mjs";
4
+ } from "./chunk-B2TXWC2C.mjs";
4
5
 
5
6
  // src/RedactoNoticeConsent/RedactoNoticeConsent.tsx
6
7
  import {
@@ -29,6 +30,64 @@ import Svg3, { Path as Path3, Rect, SvgUri } from "react-native-svg";
29
30
  // src/RedactoNoticeConsent/api/index.ts
30
31
  import { jwtDecode } from "jwt-decode";
31
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
+
32
91
  // src/constants.ts
33
92
  var DEFAULT_CONSENT_API_BASE_URL = "https://api.redacto.io/consent";
34
93
 
@@ -67,21 +126,19 @@ var fetchConsentContent = async ({
67
126
  specific_uuid,
68
127
  validate_against = "all",
69
128
  include_fully_consented_data = false,
70
- signal
129
+ signal,
130
+ ...sandboxParams
71
131
  }) => {
72
- if (!noticeId || !accessToken || !validate_against) {
73
- throw new Error("noticeId and accessToken are required");
132
+ if (!noticeId || !validate_against) {
133
+ throw new Error("noticeId is required");
74
134
  }
75
- const decodedToken = decodeTokenSafely(accessToken);
76
- if (!decodedToken) {
77
- throw new Error("Invalid access token");
78
- }
79
- const { organisation_uuid: ORGANISATION_UUID, workspace_uuid: WORKSPACE_UUID } = decodedToken;
80
- if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
81
- throw new Error("Invalid token: missing organization or workspace UUID");
135
+ if (!accessToken && !sandboxParams.token) {
136
+ throw new Error("accessToken or token is required");
82
137
  }
138
+ const { organisationUuid: ORGANISATION_UUID, workspaceUuid: WORKSPACE_UUID, sandbox } = resolveRequestAuth(accessToken, sandboxParams, decodeTokenSafely);
83
139
  const apiBaseUrl = baseUrl || DEFAULT_CONSENT_API_BASE_URL;
84
- 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}`;
85
142
  if (validate_against === "all" && !specific_uuid) {
86
143
  const cachedData = getCachedData(cacheKey);
87
144
  if (cachedData) {
@@ -98,10 +155,15 @@ var fetchConsentContent = async ({
98
155
  if (include_fully_consented_data) {
99
156
  url.searchParams.append("include_fully_consented_data", "true");
100
157
  }
158
+ if (sandbox) {
159
+ for (const [key, value] of Object.entries(sandboxQueryIdentity(sandbox))) {
160
+ url.searchParams.append(key, value);
161
+ }
162
+ }
101
163
  const response = await fetch(url.toString(), {
102
164
  method: "GET",
103
165
  headers: {
104
- Authorization: `Bearer ${accessToken}`,
166
+ ...buildAuthHeaders(accessToken, sandbox),
105
167
  "Accept-Language": language,
106
168
  "Content-Type": "application/json"
107
169
  },
@@ -141,20 +203,17 @@ var submitConsentEvent = async ({
141
203
  guardianVerificationReference,
142
204
  selfDeclaredAdult,
143
205
  language,
144
- signal
206
+ signal,
207
+ ...sandboxParams
145
208
  }) => {
146
- if (!noticeUuid || !accessToken || !Array.isArray(purposes)) {
147
- throw new Error("noticeUuid, accessToken, and purposes array are required");
209
+ if (!noticeUuid || !Array.isArray(purposes)) {
210
+ throw new Error("noticeUuid and purposes array are required");
148
211
  }
149
- const decodedToken = decodeTokenSafely(accessToken);
150
- if (!decodedToken) {
151
- throw new Error("Invalid access token");
212
+ if (!accessToken && !sandboxParams.token) {
213
+ throw new Error("accessToken or token is required");
152
214
  }
153
- const { organisation_uuid: ORGANISATION_UUID, workspace_uuid: WORKSPACE_UUID } = decodedToken;
154
- if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
155
- throw new Error("Invalid token: missing organization or workspace UUID");
156
- }
157
- 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;
158
217
  const validatedPurposes = purposes.map((purpose) => {
159
218
  if (!purpose.uuid) {
160
219
  throw new Error("Invalid purpose data: missing uuid");
@@ -180,15 +239,16 @@ var submitConsentEvent = async ({
180
239
  self_declared_adult: selfDeclaredAdult,
181
240
  language: toLanguageCode(language)
182
241
  };
242
+ const requestBody = sandbox ? { ...payload, ...sandboxBodyIdentity(sandbox) } : payload;
183
243
  const response = await fetch(
184
244
  `${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/submit-consent`,
185
245
  {
186
246
  method: "POST",
187
247
  headers: {
188
- Authorization: `Bearer ${accessToken}`,
248
+ ...buildAuthHeaders(accessToken, sandbox),
189
249
  "Content-Type": "application/json"
190
250
  },
191
- body: JSON.stringify(payload),
251
+ body: JSON.stringify(requestBody),
192
252
  signal
193
253
  }
194
254
  );
@@ -216,26 +276,27 @@ var fetchTTSAudioUrls = async ({
216
276
  baseUrl,
217
277
  noticeUuid,
218
278
  language,
219
- signal
279
+ signal,
280
+ ...sandboxParams
220
281
  }) => {
221
- if (!accessToken || !noticeUuid || !language) {
222
- throw new Error("accessToken, noticeUuid, and language are required");
223
- }
224
- const decodedToken = decodeTokenSafely(accessToken);
225
- if (!decodedToken) {
226
- throw new Error("Invalid access token");
227
- }
228
- const { organisation_uuid: ORGANISATION_UUID, workspace_uuid: WORKSPACE_UUID } = decodedToken;
229
- if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
230
- throw new Error("Invalid token: missing organization or workspace UUID");
282
+ if (!accessToken && !sandboxParams.token || !noticeUuid || !language) {
283
+ throw new Error("accessToken (or token), noticeUuid, and language are required");
231
284
  }
285
+ const { organisationUuid: ORGANISATION_UUID, workspaceUuid: WORKSPACE_UUID, sandbox } = resolveRequestAuth(accessToken, sandboxParams, decodeTokenSafely);
232
286
  const apiBaseUrl = baseUrl || DEFAULT_CONSENT_API_BASE_URL;
233
287
  const normalizedLanguage = language === "en" || language === "EN" ? "English" : language;
234
- const url = `${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/notices/${noticeUuid}/audio/${encodeURIComponent(normalizedLanguage)}`;
235
- const response = await fetch(url, {
288
+ const url = new URL(
289
+ `${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/notices/${noticeUuid}/audio/${encodeURIComponent(normalizedLanguage)}`
290
+ );
291
+ if (sandbox) {
292
+ for (const [key, value] of Object.entries(sandboxQueryIdentity(sandbox))) {
293
+ url.searchParams.append(key, value);
294
+ }
295
+ }
296
+ const response = await fetch(url.toString(), {
236
297
  method: "GET",
237
298
  headers: {
238
- Authorization: `Bearer ${accessToken}`,
299
+ ...buildAuthHeaders(accessToken, sandbox),
239
300
  Accept: "application/json",
240
301
  "Content-Type": "application/json"
241
302
  },
@@ -1749,6 +1810,12 @@ var RedactoNoticeConsent = ({
1749
1810
  noticeId,
1750
1811
  accessToken,
1751
1812
  refreshToken: _refreshToken,
1813
+ token,
1814
+ email,
1815
+ mobile,
1816
+ ucic,
1817
+ organisationUuid,
1818
+ workspaceUuid,
1752
1819
  baseUrl,
1753
1820
  ledgerBaseUrl,
1754
1821
  settings,
@@ -1764,6 +1831,16 @@ var RedactoNoticeConsent = ({
1764
1831
  }) => {
1765
1832
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u;
1766
1833
  const { isMobile } = useResponsive();
1834
+ const sandboxParams = useMemo(
1835
+ () => ({
1836
+ token,
1837
+ sandboxUcic: ucic,
1838
+ sandboxSubject: email || mobile,
1839
+ organisationUuid,
1840
+ workspaceUuid
1841
+ }),
1842
+ [token, ucic, email, mobile, organisationUuid, workspaceUuid]
1843
+ );
1767
1844
  const [content, setContent] = useState(null);
1768
1845
  const [isLoading, setIsLoading] = useState(true);
1769
1846
  const [isSubmitting, setIsSubmitting] = useState(false);
@@ -1826,12 +1903,13 @@ var RedactoNoticeConsent = ({
1826
1903
  validate_against: validateAgainst,
1827
1904
  include_fully_consented_data: includeFullyConsentedData,
1828
1905
  specific_uuid: applicationId,
1829
- signal: abortControllerRef.current.signal
1906
+ signal: abortControllerRef.current.signal,
1907
+ ...sandboxParams
1830
1908
  });
1831
1909
  const activeConfig2 = data.detail.active_config;
1832
1910
  let purposeSelections = data.detail.purpose_selections;
1833
1911
  let reconsentRequired = data.detail.reconsent_required || false;
1834
- if (ledgerBaseUrl && !applicationId) {
1912
+ if (accessToken && ledgerBaseUrl && !applicationId && !token) {
1835
1913
  const ledgerStatus = await fetchNoticeConsentStatus({
1836
1914
  accessToken,
1837
1915
  ledgerBaseUrl,
@@ -1908,7 +1986,7 @@ var RedactoNoticeConsent = ({
1908
1986
  } finally {
1909
1987
  setIsLoading(false);
1910
1988
  }
1911
- }, [noticeId, accessToken, baseUrl, ledgerBaseUrl, validateAgainst, includeFullyConsentedData, applicationId, onAccept, onError]);
1989
+ }, [noticeId, accessToken, sandboxParams, token, baseUrl, ledgerBaseUrl, validateAgainst, includeFullyConsentedData, applicationId, onAccept, onError]);
1912
1990
  useEffect2(() => {
1913
1991
  hasBootstrappedLanguageRef.current = false;
1914
1992
  }, [noticeId, accessToken]);
@@ -1930,7 +2008,8 @@ var RedactoNoticeConsent = ({
1930
2008
  accessToken,
1931
2009
  baseUrl,
1932
2010
  noticeUuid: content.detail.active_config.notice_uuid,
1933
- language: selectedLanguage
2011
+ language: selectedLanguage,
2012
+ ...sandboxParams
1934
2013
  });
1935
2014
  const urls = {
1936
2015
  notice_text: data.detail.notice_text_audio_url,
@@ -1984,7 +2063,7 @@ var RedactoNoticeConsent = ({
1984
2063
  setTtsAudioUrls({});
1985
2064
  setIsTTSAvailable(false);
1986
2065
  }
1987
- }, [content, accessToken, baseUrl, selectedLanguage]);
2066
+ }, [content, accessToken, sandboxParams, baseUrl, selectedLanguage]);
1988
2067
  const clearPlaybackWatchers = useCallback(() => {
1989
2068
  if (playbackSubscriptionRef.current) {
1990
2069
  playbackSubscriptionRef.current.remove();
@@ -2325,7 +2404,8 @@ var RedactoNoticeConsent = ({
2325
2404
  meta_data: applicationId ? { specific_uuid: applicationId } : void 0,
2326
2405
  guardianVerificationReference: verificationReferenceRef.current || void 0,
2327
2406
  selfDeclaredAdult: selfDeclaredAdult || void 0,
2328
- language: selectedLanguage
2407
+ language: selectedLanguage,
2408
+ ...sandboxParams
2329
2409
  });
2330
2410
  await stopAudio();
2331
2411
  clearApiCache();
@@ -2340,7 +2420,7 @@ var RedactoNoticeConsent = ({
2340
2420
  } finally {
2341
2421
  setIsSubmitting(false);
2342
2422
  }
2343
- }, [content, accessToken, baseUrl, ledgerBaseUrl, applicationId, selectedPurposes, selectedDataElements, selectedLanguage, stopAudio, onAccept, onError]);
2423
+ }, [content, accessToken, sandboxParams, baseUrl, ledgerBaseUrl, applicationId, selectedPurposes, selectedDataElements, selectedLanguage, selfDeclaredAdult, stopAudio, onAccept, onError]);
2344
2424
  const handleDecline = useCallback(() => {
2345
2425
  stopAudio();
2346
2426
  stopPolling();
@@ -2955,14 +3035,16 @@ var fetchConsentContent2 = async ({
2955
3035
  org_uuid,
2956
3036
  workspace_uuid,
2957
3037
  notice_uuid,
3038
+ accessToken,
2958
3039
  baseUrl,
2959
3040
  language = "en",
2960
3041
  specific_uuid,
2961
3042
  signal
2962
3043
  }) => {
2963
3044
  const apiBaseUrl = baseUrl || DEFAULT_CONSENT_API_BASE_URL;
3045
+ const noticesUrl = `${apiBaseUrl}/public/organisations/${org_uuid}/workspaces/${workspace_uuid}/notices`;
2964
3046
  const url = new URL(
2965
- `${apiBaseUrl}/public/organisations/${org_uuid}/workspaces/${workspace_uuid}/notices/get-notice/${notice_uuid}`
3047
+ accessToken ? `${noticesUrl}/${notice_uuid}` : `${noticesUrl}/get-notice/${notice_uuid}`
2966
3048
  );
2967
3049
  if (specific_uuid) {
2968
3050
  url.searchParams.append("specific_uuid", specific_uuid);
@@ -2971,7 +3053,8 @@ var fetchConsentContent2 = async ({
2971
3053
  method: "GET",
2972
3054
  headers: {
2973
3055
  "Content-Type": "application/json",
2974
- "Accept-Language": language
3056
+ "Accept-Language": language,
3057
+ ...accessToken ? { Authorization: `Bearer ${accessToken}` } : {}
2975
3058
  },
2976
3059
  signal
2977
3060
  });
@@ -3412,11 +3495,13 @@ var RedactoConsentInlineComponent = ({
3412
3495
  const fetchNotice = useCallback2(async (signal) => {
3413
3496
  setIsLoading(true);
3414
3497
  setFetchError(null);
3498
+ setHasAlreadyConsented(false);
3415
3499
  try {
3416
3500
  const consentContentData = await fetchConsentContent2({
3417
3501
  org_uuid,
3418
3502
  workspace_uuid,
3419
3503
  notice_uuid,
3504
+ accessToken,
3420
3505
  baseUrl,
3421
3506
  language,
3422
3507
  specific_uuid: applicationId,
@@ -3466,7 +3551,7 @@ var RedactoConsentInlineComponent = ({
3466
3551
  setIsLoading(false);
3467
3552
  }
3468
3553
  }
3469
- }, [org_uuid, workspace_uuid, notice_uuid, baseUrl, language, applicationId, onError]);
3554
+ }, [org_uuid, workspace_uuid, notice_uuid, accessToken, baseUrl, language, applicationId, onError]);
3470
3555
  useEffect3(() => {
3471
3556
  const controller = new AbortController();
3472
3557
  void fetchNotice(controller.signal);
@@ -301,6 +301,7 @@ type UserConsent = {
301
301
  product_name?: string;
302
302
  product_description?: string | null;
303
303
  nominator_info?: NominatorInfo;
304
+ revoke_warning_message?: string | null;
304
305
  notice_uuid?: string | null;
305
306
  };
306
307
  type NominatorInfo = {
@@ -333,6 +334,7 @@ type PurposeItem = {
333
334
  method: string;
334
335
  data_elements: ConsentDataElement[];
335
336
  link_reason: string | null;
337
+ revoke_warning_message?: string | null;
336
338
  notice_uuid?: string | null;
337
339
  };
338
340
  type ConsentGroup = {
@@ -512,15 +514,38 @@ interface RedactoPrivacyCenterProps {
512
514
  * Accepted for backwards compatibility but ignored.
513
515
  */
514
516
  theme?: 'light' | 'dark';
515
- accessToken: string;
516
- refreshToken: string;
517
+ /** JWT access token. Optional so sandbox mode (see `token`) can omit it. */
518
+ accessToken?: string;
519
+ /** JWT refresh token. Optional; used by the OTP-refresh loop in the JWT flow. */
520
+ refreshToken?: string;
521
+ /**
522
+ * Sandbox PoC: a pasted static token. When set, the Privacy Center runs
523
+ * against the sandbox with no JWT — it sends the single `X-Consent-Token`
524
+ * header, carries the acting identity (`email` || `mobile`) in each request's
525
+ * own payload, takes org/workspace from `organisationUuid`/`workspaceUuid`,
526
+ * and never calls `/otp/refresh`.
527
+ */
528
+ token?: string;
529
+ /** Sandbox test subject email (carried in the request payload when set). */
530
+ email?: string;
531
+ /** Sandbox test subject mobile (fallback subject when `email` is absent). */
532
+ mobile?: string;
533
+ /**
534
+ * Sandbox UCIC: the client's own user id / org_user_id, e.g. a UUID or
535
+ * customer code; optional third identifier alongside email/mobile.
536
+ */
537
+ ucic?: string;
538
+ /** Sandbox org UUID (replaces the JWT-decoded org in sandbox mode). */
539
+ organisationUuid?: string;
540
+ /** Sandbox workspace UUID (replaces the JWT-decoded workspace in sandbox mode). */
541
+ workspaceUuid?: string;
517
542
  onError: (error: Error) => boolean;
518
543
  initialPage?: InternalPage;
519
544
  /** Optional deep-link: open a specific case (use with initialPage='case-details'). */
520
545
  initialCaseUuid?: string;
521
546
  onBack?: 'back' | 'signout';
522
547
  }
523
- declare function RedactoPrivacyCenter({ baseUrl, ledgerBaseUrl, slug, theme: _theme, accessToken, refreshToken, onError, initialPage, initialCaseUuid, onBack, }: RedactoPrivacyCenterProps): React.JSX.Element;
548
+ declare function RedactoPrivacyCenter({ baseUrl, ledgerBaseUrl, slug, theme: _theme, accessToken, refreshToken, token, email, mobile, ucic, organisationUuid, workspaceUuid, onError, initialPage, initialCaseUuid, onBack, }: RedactoPrivacyCenterProps): React.JSX.Element;
524
549
 
525
550
  declare function ConsentManager(): React__default.JSX.Element;
526
551
 
@@ -876,9 +901,26 @@ interface AuthProviderProps {
876
901
  children: ReactNode;
877
902
  accessToken: string;
878
903
  refreshToken: string;
904
+ /**
905
+ * Sandbox PoC: when set, the Privacy Center skips the JWT entirely — it seeds
906
+ * org/workspace/subject from the props below, sends the single
907
+ * `X-Consent-Token` header, carries the acting identity in each request's own
908
+ * payload, and never calls `/otp/refresh`.
909
+ */
910
+ token?: string;
911
+ /** Sandbox UCIC — the client's own user id (`org_user_id`); takes precedence over the subject. */
912
+ sandboxUcic?: string;
913
+ /** Sandbox subject (email or mobile) — carried in the request payload. */
914
+ sandboxSubject?: string;
915
+ /** Sandbox org UUID (replaces the JWT-decoded org). */
916
+ organisationUuid?: string;
917
+ /** Sandbox workspace UUID (replaces the JWT-decoded workspace). */
918
+ workspaceUuid?: string;
919
+ /** Organisation slug — used to seed the sandbox config. */
920
+ slug?: string;
879
921
  onError: (error: Error) => boolean;
880
922
  }
881
- declare function AuthProvider({ children, accessToken: initialAccessToken, refreshToken: initialRefreshToken, onError }: AuthProviderProps): React.JSX.Element;
923
+ declare function AuthProvider(props: AuthProviderProps): React.JSX.Element;
882
924
  declare function useAuth(): AuthContextType;
883
925
 
884
926
  /**
@@ -301,6 +301,7 @@ type UserConsent = {
301
301
  product_name?: string;
302
302
  product_description?: string | null;
303
303
  nominator_info?: NominatorInfo;
304
+ revoke_warning_message?: string | null;
304
305
  notice_uuid?: string | null;
305
306
  };
306
307
  type NominatorInfo = {
@@ -333,6 +334,7 @@ type PurposeItem = {
333
334
  method: string;
334
335
  data_elements: ConsentDataElement[];
335
336
  link_reason: string | null;
337
+ revoke_warning_message?: string | null;
336
338
  notice_uuid?: string | null;
337
339
  };
338
340
  type ConsentGroup = {
@@ -512,15 +514,38 @@ interface RedactoPrivacyCenterProps {
512
514
  * Accepted for backwards compatibility but ignored.
513
515
  */
514
516
  theme?: 'light' | 'dark';
515
- accessToken: string;
516
- refreshToken: string;
517
+ /** JWT access token. Optional so sandbox mode (see `token`) can omit it. */
518
+ accessToken?: string;
519
+ /** JWT refresh token. Optional; used by the OTP-refresh loop in the JWT flow. */
520
+ refreshToken?: string;
521
+ /**
522
+ * Sandbox PoC: a pasted static token. When set, the Privacy Center runs
523
+ * against the sandbox with no JWT — it sends the single `X-Consent-Token`
524
+ * header, carries the acting identity (`email` || `mobile`) in each request's
525
+ * own payload, takes org/workspace from `organisationUuid`/`workspaceUuid`,
526
+ * and never calls `/otp/refresh`.
527
+ */
528
+ token?: string;
529
+ /** Sandbox test subject email (carried in the request payload when set). */
530
+ email?: string;
531
+ /** Sandbox test subject mobile (fallback subject when `email` is absent). */
532
+ mobile?: string;
533
+ /**
534
+ * Sandbox UCIC: the client's own user id / org_user_id, e.g. a UUID or
535
+ * customer code; optional third identifier alongside email/mobile.
536
+ */
537
+ ucic?: string;
538
+ /** Sandbox org UUID (replaces the JWT-decoded org in sandbox mode). */
539
+ organisationUuid?: string;
540
+ /** Sandbox workspace UUID (replaces the JWT-decoded workspace in sandbox mode). */
541
+ workspaceUuid?: string;
517
542
  onError: (error: Error) => boolean;
518
543
  initialPage?: InternalPage;
519
544
  /** Optional deep-link: open a specific case (use with initialPage='case-details'). */
520
545
  initialCaseUuid?: string;
521
546
  onBack?: 'back' | 'signout';
522
547
  }
523
- declare function RedactoPrivacyCenter({ baseUrl, ledgerBaseUrl, slug, theme: _theme, accessToken, refreshToken, onError, initialPage, initialCaseUuid, onBack, }: RedactoPrivacyCenterProps): React.JSX.Element;
548
+ declare function RedactoPrivacyCenter({ baseUrl, ledgerBaseUrl, slug, theme: _theme, accessToken, refreshToken, token, email, mobile, ucic, organisationUuid, workspaceUuid, onError, initialPage, initialCaseUuid, onBack, }: RedactoPrivacyCenterProps): React.JSX.Element;
524
549
 
525
550
  declare function ConsentManager(): React__default.JSX.Element;
526
551
 
@@ -876,9 +901,26 @@ interface AuthProviderProps {
876
901
  children: ReactNode;
877
902
  accessToken: string;
878
903
  refreshToken: string;
904
+ /**
905
+ * Sandbox PoC: when set, the Privacy Center skips the JWT entirely — it seeds
906
+ * org/workspace/subject from the props below, sends the single
907
+ * `X-Consent-Token` header, carries the acting identity in each request's own
908
+ * payload, and never calls `/otp/refresh`.
909
+ */
910
+ token?: string;
911
+ /** Sandbox UCIC — the client's own user id (`org_user_id`); takes precedence over the subject. */
912
+ sandboxUcic?: string;
913
+ /** Sandbox subject (email or mobile) — carried in the request payload. */
914
+ sandboxSubject?: string;
915
+ /** Sandbox org UUID (replaces the JWT-decoded org). */
916
+ organisationUuid?: string;
917
+ /** Sandbox workspace UUID (replaces the JWT-decoded workspace). */
918
+ workspaceUuid?: string;
919
+ /** Organisation slug — used to seed the sandbox config. */
920
+ slug?: string;
879
921
  onError: (error: Error) => boolean;
880
922
  }
881
- declare function AuthProvider({ children, accessToken: initialAccessToken, refreshToken: initialRefreshToken, onError }: AuthProviderProps): React.JSX.Element;
923
+ declare function AuthProvider(props: AuthProviderProps): React.JSX.Element;
882
924
  declare function useAuth(): AuthContextType;
883
925
 
884
926
  /**