@redacto.io/consent-sdk-react 10.4.0-beta.1 → 11.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -117,6 +117,67 @@ npm install @tanstack/react-query @tanstack/react-table \
117
117
 
118
118
  If you only use `RedactoNoticeConsent` or `RedactoNoticeConsentInline`, these peers are not needed.
119
119
 
120
+ ### API host (`baseUrl`)
121
+
122
+ Pass the Redacto **API host** as `baseUrl`, for example `https://api.redacto.io`. Every component, `createConsentClient` and `BaseUrlProvider` take it, and the SDK reaches each backend service under it:
123
+
124
+ | Service | URL |
125
+ | --- | --- |
126
+ | Consent server | `{baseUrl}/consent` |
127
+ | Consent ledger | `{baseUrl}/consent-ledger` |
128
+ | User service (Privacy Center branding) | `{baseUrl}/user/api/0` |
129
+
130
+ A host behind a path prefix works the same way: `https://gateway.example.com/redacto` reaches the consent server at `https://gateway.example.com/redacto/consent`, and so on.
131
+
132
+ | Request | Service |
133
+ | --- | --- |
134
+ | `RedactoNoticeConsent` notice read | Ledger with a JWT; consent server in sandbox and in the magic-link (`applicationId`) flow |
135
+ | `RedactoNoticeConsent` notice audio | Ledger, sandbox included |
136
+ | `RedactoNoticeConsentInline` notice read | Ledger with an `accessToken`; consent server without one and in the magic-link (`applicationId`) flow |
137
+ | Consent writes (`submit-consent`) and the already-consented check (`check-consent`) | Ledger |
138
+ | `RedactoNoticeAssisted` notice, audio and OTP; guardian verification (DigiLocker) | Consent server |
139
+ | Privacy Center user consents, product purposes, receipts, manage consent | Ledger |
140
+ | Privacy Center DSAR form, cases, activities, identities, OTP, token exchange, notifications, uploads, products, settings | Consent server |
141
+ | Privacy Center org branding (by organisation UUID) | User service |
142
+
143
+ For custom Privacy Center compositions, `useBaseUrl()` returns the consent server URL as `baseUrl`, the ledger URL as `ledgerBaseUrl` and the host as `apiHost`.
144
+
145
+ #### The consent server URL (deprecated, still supported)
146
+
147
+ Earlier releases documented the **consent server URL** as `baseUrl` (`https://api.redacto.io/consent`), with an optional `ledgerBaseUrl`. Both keep working exactly as before, so upgrading changes nothing until you switch:
148
+
149
+ - With the consent server URL, every request goes where earlier releases sent it. Consent writes, the already-consented check and the Privacy Center's consents and receipts use the ledger only when `ledgerBaseUrl` is set; without it they stay on the consent server's legacy routes. `useBaseUrl()` returns both values as passed, with `apiHost` undefined.
150
+ - Without `baseUrl`, the notice components still use the built-in production default.
151
+ - The SDK tells the two apart by shape: an absolute `http(s)` URL that does not end in `/consent` is the API host; anything else (omitted, ending in `/consent`, or relative) is used as passed. A `baseUrl` ending in `/consent-ledger` resolves to its host the same way, so the ledger URL earlier releases took as `ledgerBaseUrl` also works as `baseUrl`. A consent server that is not mounted at `/consent` is therefore read as a host, so keep passing its URL ending in `/consent` until you switch.
152
+ - Each deprecated form logs one console warning per page load; passing the host clears them.
153
+
154
+ Compared with the consent server URL plus `ledgerBaseUrl`, the host changes two routes: `RedactoNoticeConsentInline` reads its notice from the ledger when it has an `accessToken`, and `RedactoNoticeConsent` plays sandbox audio from the ledger. The user service also keeps any path prefix of the host.
155
+
156
+ #### `ledgerBaseUrl` (deprecated)
157
+
158
+ Read only when `baseUrl` is the consent server URL (`…/consent`) or omitted, as in earlier releases. Ignored when `baseUrl` is the API host: the ledger is then always `{baseUrl}/consent-ledger`, and the SDK logs one console warning asking you to remove `ledgerBaseUrl`.
159
+
160
+ #### Local development
161
+
162
+ Put the services behind one local gateway, the way production does, and pass its address as `baseUrl`. For example, with [Caddy](https://caddyserver.com), the consent server on port 8000 and the ledger on port 8090:
163
+
164
+ ```caddyfile
165
+ :8080 {
166
+ handle /consent-ledger/* {
167
+ reverse_proxy localhost:8090
168
+ }
169
+ handle /consent/* {
170
+ reverse_proxy localhost:8000
171
+ }
172
+ }
173
+ ```
174
+
175
+ Then pass `baseUrl="http://localhost:8080"`. Both services serve their own path prefix (`/consent/…`, `/consent-ledger/…`), so the gateway forwards paths unchanged. Any reverse proxy works the same way (nginx, Traefik, your docker-compose gateway).
176
+
177
+ #### When your backend reuses the value
178
+
179
+ Your backend's token calls go to the consent server. If your frontend sends its `baseUrl` to your backend (as `base_url` in [Backend Server Setup](#backend-server-setup)), the backend appends `/consent` to the host: `{host}/consent/public/organisations/{organisation_uuid}/workspaces/{workspace_uuid}/tokens/generate`. A backend that still receives the consent server URL keeps appending `/public/...` to it directly.
180
+
120
181
  ## Sandbox Mode (No Backend Required)
121
182
 
122
183
  Sandbox mode lets you build and test a full consent PoC — **notice → Privacy Center → DSAR** — straight from your app, with **no backend and no token minting**. Instead of your server generating a JWT, you paste a **static sandbox token** into the SDK. Everything you create is recorded as test data, isolated from your live records.
@@ -138,6 +199,7 @@ Pass the sandbox `token`, org/workspace, and a test identity (`email`, `mobile`,
138
199
  import { RedactoNoticeConsent } from "@redacto.io/consent-sdk-react";
139
200
 
140
201
  <RedactoNoticeConsent
202
+ baseUrl="https://api.redacto.io"
141
203
  noticeId={NOTICE_UUID}
142
204
  token={SANDBOX_TOKEN}
143
205
  organisationUuid={ORG_UUID}
@@ -156,11 +218,11 @@ Point the Privacy Center at the same sandbox token and test identity. The same t
156
218
  import { RedactoPrivacyCenter } from "@redacto.io/consent-sdk-react/privacy-center";
157
219
 
158
220
  <RedactoPrivacyCenter
221
+ baseUrl="https://api.redacto.io"
159
222
  token={SANDBOX_TOKEN}
160
223
  organisationUuid={ORG_UUID}
161
224
  workspaceUuid={WORKSPACE_UUID}
162
225
  email="test.user@example.com" // or `mobile`, or `ucic`
163
- slug="acme-co"
164
226
  onError={(error) => {
165
227
  console.error(error);
166
228
  return false;
@@ -183,7 +245,7 @@ import { RedactoPrivacyCenter } from "@redacto.io/consent-sdk-react/privacy-cent
183
245
 
184
246
  - The SDK sends the sandbox token as an `X-Consent-Token` header and the test identity inside each request (query params on reads, body on writes) — no JWT decode, no token refresh (a `401` fails fast).
185
247
  - The server records everything under `environment=test`, namespaced so sandbox data never mixes with — or reads — your live records.
186
- - Sandbox always talks to the consent server; it never routes to the Go ledger.
248
+ - Sandbox requests go to the same services as live ones (see [API host](#api-host-baseurl)), except that the notice read stays on the consent server.
187
249
 
188
250
  ### Going live
189
251
 
@@ -216,6 +278,7 @@ app.post(
216
278
  async (req: Request, res: Response): Promise<void> => {
217
279
  try {
218
280
  const { email } = req.body;
281
+ // base_url is the API host the frontend passes as baseUrl, e.g. https://api.redacto.io
219
282
  const { organisation_uuid, workspace_uuid, base_url } = req.query;
220
283
 
221
284
  if (!CMS_API_KEY) {
@@ -224,7 +287,7 @@ app.post(
224
287
 
225
288
  // Call Redacto API to generate access token
226
289
  const response = await axios.post(
227
- `${base_url}/public/organisations/${organisation_uuid}/workspaces/${workspace_uuid}/tokens/generate-access-token`,
290
+ `${base_url}/consent/public/organisations/${organisation_uuid}/workspaces/${workspace_uuid}/tokens/generate`,
228
291
  {
229
292
  email,
230
293
  // expires_in_days: 1, // Optional: set token expiration
@@ -263,7 +326,7 @@ app.post(
263
326
 
264
327
  // Call Redacto API to refresh access token
265
328
  const response = await axios.post(
266
- `${base_url}/consent/public/organisations/${organisation_uuid}/workspaces/${workspace_uuid}/tokens/refresh-token`,
329
+ `${base_url}/consent/public/organisations/${organisation_uuid}/workspaces/${workspace_uuid}/tokens/refresh`,
267
330
  { refresh_token: refresh_token },
268
331
  {
269
332
  headers: {
@@ -287,16 +350,16 @@ app.post(
287
350
 
288
351
  #### Redacto API Endpoints Used
289
352
 
290
- Your backend needs to call the following Redacto API endpoints:
353
+ Your backend needs to call the following Redacto API endpoints on the API host (e.g. `https://api.redacto.io`):
291
354
 
292
355
  1. **Generate Access Token**
293
- - **Endpoint**: `POST /public/organisations/{organisation_uuid}/workspaces/{workspace_uuid}/tokens/generate-access-token`
356
+ - **Endpoint**: `POST /consent/public/organisations/{organisation_uuid}/workspaces/{workspace_uuid}/tokens/generate`
294
357
  - **Headers**: `X-CMS-API-Key: {your-cms-api-key}`
295
358
  - **Body**: `{ email, expires_in_days? }`
296
359
  - **Response**: `{ detail: { token, refresh_token, expires_at } }`
297
360
 
298
361
  2. **Refresh Access Token**
299
- - **Endpoint**: `POST /consent/public/organisations/{organisation_uuid}/workspaces/{workspace_uuid}/tokens/refresh-token`
362
+ - **Endpoint**: `POST /consent/public/organisations/{organisation_uuid}/workspaces/{workspace_uuid}/tokens/refresh`
300
363
  - **Headers**: `X-CMS-API-Key: {your-cms-api-key}`
301
364
  - **Body**: `{ refresh_token }`
302
365
  - **Response**: `{ detail: { token, refresh_token, expires_at } }`
@@ -322,8 +385,8 @@ A modal popup component for consent collection. Displays a full-screen modal wit
322
385
  | `noticeId` | `string` | Yes | - | UUID of the consent notice |
323
386
  | `accessToken` | `string` | Yes | - | Authentication token for API calls |
324
387
  | `refreshToken` | `string` | Yes | - | Refresh token for token renewal |
325
- | `baseUrl` | `string` | No | - | Base URL for the consent API |
326
- | `ledgerBaseUrl` | `string` | No | - | Go ledger base URL. When set, consent writes and prior-consent checks route through the ledger (falls back: ledger → baseUrl → default). Omit to keep the legacy consent-server path. |
388
+ | `baseUrl` | `string` | No | Production API | API host, e.g. `https://api.redacto.io` (see [API host](#api-host-baseurl)). The consent server URL (`…/consent`) still works but is deprecated |
389
+ | `ledgerBaseUrl` | `string` | No | - | **Deprecated.** Read only when `baseUrl` is the consent server URL (`…/consent`) or omitted, as in earlier releases. Ignored when `baseUrl` is the API host. There, it routes consent writes and prior-consent checks through the ledger (falls back: ledger → baseUrl → default) |
327
390
  | `blockUI` | `boolean` | No | `true` | Whether to block UI interaction |
328
391
  | `language` | `string` | No | `"en"` | Language code |
329
392
  | `settings` | `object` | No | - | Optional code overrides; win over the console appearance key by key. See [Appearance](#notice-appearance) |
@@ -409,8 +472,8 @@ The component automatically submits consent when all of the following conditions
409
472
  | `notice_uuid` | `string` | Yes | - | Notice UUID |
410
473
  | `accessToken` | `string` | No | - | Authentication token |
411
474
  | `refreshToken` | `string` | No | - | Refresh token |
412
- | `baseUrl` | `string` | No | - | Base URL for the consent API |
413
- | `ledgerBaseUrl` | `string` | No | - | Go ledger base URL. When set, consent writes and already-consented checks route through the ledger. Omit for legacy behavior. |
475
+ | `baseUrl` | `string` | No | Production API | API host, e.g. `https://api.redacto.io` (see [API host](#api-host-baseurl)). The consent server URL (`…/consent`) still works but is deprecated |
476
+ | `ledgerBaseUrl` | `string` | No | - | **Deprecated.** Read only when `baseUrl` is the consent server URL (`…/consent`) or omitted, as in earlier releases. Ignored when `baseUrl` is the API host. There, it routes consent writes and already-consented checks through the ledger |
414
477
  | `language` | `string` | No | `"en"` | Language code |
415
478
  | `settings` | `object` | No | - | Optional code overrides of the console appearance |
416
479
  | `applicationId` | `string` | No | - | Application-specific UUID |
@@ -440,8 +503,8 @@ A modal, agent-assisted consent widget for collecting consent from an end-user w
440
503
  | `organisationUuid` | `string` | Yes | - | Organisation UUID (path segment of the public notice endpoint) |
441
504
  | `workspaceUuid` | `string` | Yes | - | Workspace UUID (path segment of the public notice endpoint) |
442
505
  | `noticeUuid` | `string` | Yes | - | Notice UUID to fetch and render |
443
- | `baseUrl` | `string` | No | Production consent API | Base URL for the consent API |
444
- | `ledgerBaseUrl` | `string` | No | - | Go ledger base URL. When set, the consent write routes through the ledger (falls back: ledger → baseUrl → default). Notice fetch, OTP, and TTS always stay on `baseUrl`. Omit for legacy behavior. |
506
+ | `baseUrl` | `string` | No | Production API | API host, e.g. `https://api.redacto.io` (see [API host](#api-host-baseurl)). The consent server URL (`…/consent`) still works but is deprecated |
507
+ | `ledgerBaseUrl` | `string` | No | - | **Deprecated.** Read only when `baseUrl` is the consent server URL (`…/consent`) or omitted, as in earlier releases. Ignored when `baseUrl` is the API host. There, it routes the consent write through the ledger (falls back: ledger → baseUrl → default); notice fetch, OTP, and TTS stay on the consent server |
445
508
  | `onDecline` | `() => void` | No | Logs and resets the flow | Called when the agent/customer declines (host should unmount the modal) |
446
509
  | `onComplete` | `() => void` | No | Logs and resets the flow | Called when the agent clicks "Proceed" on the confirmed screen |
447
510
 
@@ -478,6 +541,7 @@ function SignUpPage() {
478
541
 
479
542
  try {
480
543
  // Step 1: Get tokens from your backend
544
+ // BASE_URL is the Redacto API host, e.g. https://api.redacto.io
481
545
  const response = await fetch(
482
546
  `${BACKEND_URL}/api/consent/token?workspace_uuid=${WORKSPACE_UUID}&organisation_uuid=${ORG_UUID}&base_url=${BASE_URL}`,
483
547
  {
@@ -715,7 +779,7 @@ import { RedactoNoticeAssisted } from "@redacto.io/consent-sdk-react";
715
779
  const ORG_UUID = "your-organisation-uuid";
716
780
  const WORKSPACE_UUID = "your-workspace-uuid";
717
781
  const NOTICE_UUID = "your-notice-uuid";
718
- const BASE_URL = "https://api.redacto.io/consent"; // Optional: override the consent API
782
+ const BASE_URL = "https://api.redacto.io"; // The Redacto API host
719
783
 
720
784
  export function AssistedConsent() {
721
785
  const [open, setOpen] = useState(false);
@@ -960,7 +1024,6 @@ import { RedactoPrivacyCenter } from "@redacto.io/consent-sdk-react/privacy-cent
960
1024
 
961
1025
  <RedactoPrivacyCenter
962
1026
  baseUrl={BASE_URL}
963
- slug="acme-co"
964
1027
  accessToken={accessToken}
965
1028
  refreshToken={refreshToken}
966
1029
  settings={{ theme: "glass" }}
@@ -976,13 +1039,13 @@ import { RedactoPrivacyCenter } from "@redacto.io/consent-sdk-react/privacy-cent
976
1039
 
977
1040
  | Prop | Type | Required | Default | Description |
978
1041
  | ----------------- | ------------------------------------------------- | -------- | ------------------- | ----------- |
979
- | `baseUrl` | `string` | Yes | - | Consent server base URL |
980
- | `ledgerBaseUrl` | `string` | No | - | Go ledger base URL. When set, user consents, group purposes, receipts, and manage-consent route through the ledger, and the DSAR form's product picker is overlaid from ledger-served consents. Omit to use the legacy `/dsar/privacy-center/*` routes. |
981
- | `slug` | `string` | Yes | - | Organisation slug |
1042
+ | `baseUrl` | `string` | Yes | - | API host, e.g. `https://api.redacto.io` (see [API host](#api-host-baseurl)). The consent server URL (`…/consent`) still works but is deprecated |
1043
+ | `ledgerBaseUrl` | `string` | No | - | **Deprecated.** Read only when `baseUrl` is the consent server URL (`…/consent`) or omitted, as in earlier releases. Ignored when `baseUrl` is the API host. There, it routes user consents, group purposes, receipts, and manage-consent through the ledger and overlays the DSAR form's product picker from ledger-served consents; omitted, the legacy `/dsar/privacy-center/*` routes are used |
1044
+ | `slug` | `string` | No | - | **Deprecated** and ignored; will be removed in a future major release. Passing it logs a one-time console warning. The organisation comes from the access token, or from `organisationUuid` and `workspaceUuid` |
982
1045
  | `accessToken` | `string` | No | - | JWT access token. Without one the Privacy Center waits for it, or shows its built-in sign-in when `builtInSignIn` is on (see [Sign-in](#privacy-center-sign-in)) |
983
1046
  | `refreshToken` | `string` | No | - | JWT refresh token |
984
- | `organisationUuid`| `string` | No | - | Organisation UUID for sign-in and settings when there is no token; looked up from `slug` when omitted (also the sandbox org) |
985
- | `workspaceUuid` | `string` | No | - | Workspace UUID for sign-in when there is no token; looked up from `slug` when omitted (also the sandbox workspace) |
1047
+ | `organisationUuid`| `string` | No | - | Organisation UUID for sign-in, settings and branding when there is no token; the built-in sign-in needs it with `workspaceUuid` (also the sandbox org) |
1048
+ | `workspaceUuid` | `string` | No | - | Workspace UUID for sign-in when there is no token; the built-in sign-in needs it with `organisationUuid` (also the sandbox workspace) |
986
1049
  | `onError` | `(error: Error) => boolean` | Yes | - | Error handler; return `true` if handled |
987
1050
  | `settings` | `PrivacyCenterSettings` | No | - | Overrides for the settings published from the console, merged field by field per group (see [Settings](#privacy-center-settings)). `theme` is kept as an alias for `branding.style` |
988
1051
  | `builtInSignIn` | `boolean` | No | `false` | Show the built-in OTP sign-in when there is no token. Off, the Privacy Center keeps its loading state until the host passes a token |
@@ -1016,7 +1079,7 @@ type PrivacyCenterRequestSubmission = {
1016
1079
 
1017
1080
  ### Settings
1018
1081
 
1019
- The Privacy Center reads the settings an admin publishes in the Redacto console (Rights Management › Privacy Center › Settings) from the public endpoint `GET {baseUrl}/public/organisations/{organisation_uuid}/privacy-center-settings/?lang={language}`. The organisation comes from `organisationUuid`, the access token, the session, or a lookup by `slug`. The settings are fetched again, localised, when the visitor changes language, and cached in memory per organisation and language.
1082
+ The Privacy Center reads the settings an admin publishes in the Redacto console (Rights Management › Privacy Center › Settings) from the consent server's public endpoint `GET {consent server}/public/organisations/{organisation_uuid}/privacy-center-settings/?lang={language}` (`{baseUrl}/consent/public/...` with the API host). The organisation comes from `organisationUuid`, the access token, or the session. The settings are fetched again, localised, when the visitor changes language, and cached in memory per organisation and language.
1020
1083
 
1021
1084
  Rendering never waits for them: the Privacy Center starts with the defaults and swaps the published values in when they arrive. **With nothing published, or if the request fails, it looks and behaves exactly as before settings existed.**
1022
1085
 
@@ -1039,7 +1102,6 @@ Override any of it in code; each group merges field by field over what was publi
1039
1102
  ```tsx
1040
1103
  <RedactoPrivacyCenter
1041
1104
  baseUrl={BASE_URL}
1042
- slug="acme-co"
1043
1105
  accessToken={accessToken}
1044
1106
  onError={() => false}
1045
1107
  settings={{
@@ -1059,7 +1121,13 @@ The full shape is exported as `ResolvedPrivacyCenterSettings` (with `DEFAULT_PRI
1059
1121
  Pass `builtInSignIn` and, with no `accessToken`, the Privacy Center shows its own sign-in instead of a loader: the visitor enters a mobile number or email, receives a one-time code (resend after 50 seconds) and is signed straight in with the tokens it issues. Layout (card, split or minimal), background, copy, channels (SMS, email or both), default country code, notice line and support link come from the `sign_in` settings. It is off by default, so a host that passes its token a moment after mounting never flashes a sign-in screen.
1060
1122
 
1061
1123
  ```tsx
1062
- <RedactoPrivacyCenter baseUrl={BASE_URL} slug="acme-co" builtInSignIn onError={() => false} />
1124
+ <RedactoPrivacyCenter
1125
+ baseUrl={BASE_URL}
1126
+ organisationUuid={ORG_UUID}
1127
+ workspaceUuid={WORKSPACE_UUID}
1128
+ builtInSignIn
1129
+ onError={() => false}
1130
+ />
1063
1131
  ```
1064
1132
 
1065
1133
  ### Custom CSS
@@ -1109,11 +1177,11 @@ These rely on the same context providers (`AuthProvider`, `BaseUrlProvider`, `Na
1109
1177
 
1110
1178
  For consumers who want their own UI, the headless core exposes the API client, orchestration helpers, hooks, and auth utilities:
1111
1179
 
1112
- - **API client**: `createConsentClient` (returns a typed `BaseRequest`-aware fetcher)
1180
+ - **API client**: `createConsentClient(baseUrl, ledgerBaseUrl?)` (takes the API host, like the components; returns a typed `BaseRequest`-aware fetcher that picks the service per request. The consent server URL and `ledgerBaseUrl` still work as before, deprecated; `ledgerBaseUrl` is ignored with the API host)
1113
1181
  - **Orchestration helpers** (handle auth retry / token refresh internally): `getFormData`, `createCaseRequest`, `fetchProducts`, `fetchUserConsents`, `manageConsent`, `fetchActivities`, `fetchCaseHistory`, `createOtp`, `verifyOtp`, `exchangeToken`
1114
1182
  - **Auth utilities**: `decodeJwtToken`, `isJwtExpired`, `ensureValidToken`, `signOutPrivacyCenter`, `getCookieValue`, `setRefreshTokenCookie`, `checkAndRefreshAuth`, `compareEmails`, `isUserAuthenticated`, `getInitialState`, `getActivityTypeStatus`, `formatActivityType`
1115
1183
  - **React Query hook**: `useCaseHistory`
1116
- - **Context providers**: `AuthProvider` + `useAuth`, `BaseUrlProvider` + `useBaseUrl`, `NavigationProvider` + `useInternalNavigation`
1184
+ - **Context providers**: `AuthProvider` + `useAuth`, `BaseUrlProvider` + `useBaseUrl` (`BaseUrlProvider` takes the API host as `baseUrl`; `useBaseUrl()` returns the consent server URL as `baseUrl`, the ledger URL as `ledgerBaseUrl`, the host as `apiHost` and the client), `NavigationProvider` + `useInternalNavigation`
1117
1185
  - **Types**: `Workspace`, `OrganizationDetail`, `DataElement`, `Purpose`, `UserConsent`, `Activity`, `CaseHistoryDetail`, `RequestTypeEnum`, `GrievanceTypeEnum`, `ConsentStatusEnum`, and more (see `privacy-center.ts` for the full export list)
1118
1186
 
1119
1187
  ### Style Injection
@@ -1166,7 +1234,7 @@ injectPCStyles();
1166
1234
  - Verify authentication setup is correct for your environment
1167
1235
  - Check that API key generation is working
1168
1236
  - Ensure organisation and workspace UUIDs are correct
1169
- - Verify base URL matches your environment (staging vs production)
1237
+ - Verify `base_url` is your environment's API host (staging vs production) and that your backend calls the consent server under it (`{host}/consent/...`)
1170
1238
 
1171
1239
  ### Validation not working
1172
1240
 
@@ -1178,11 +1246,11 @@ injectPCStyles();
1178
1246
 
1179
1247
  ### Redacto CMP API Endpoints
1180
1248
 
1181
- The SDK communicates with Redacto's CMP API. Key endpoints used:
1249
+ The SDK communicates with Redacto's CMP API on the API host (see [API host](#api-host-baseurl)). Key endpoints used:
1182
1250
 
1183
- - **Get Consent Notice**: `GET /public/organisations/{org_uuid}/workspaces/{workspace_uuid}/notices/{notice_uuid}`
1184
- - **Submit Consent**: `POST /public/organisations/{org_uuid}/workspaces/{workspace_uuid}/submit-consent`
1185
- - **Generate Access Token**: `POST /public/organisations/{org_uuid}/workspaces/{workspace_uuid}/tokens/generate-access-token`
1251
+ - **Get Consent Notice** (JWT session): `GET {baseUrl}/consent-ledger/public/organisations/{org_uuid}/workspaces/{workspace_uuid}/notices/{notice_uuid}`
1252
+ - **Submit Consent**: `POST {baseUrl}/consent-ledger/public/organisations/{org_uuid}/workspaces/{workspace_uuid}/submit-consent`
1253
+ - **Generate Access Token** (your backend): `POST {baseUrl}/consent/public/organisations/{org_uuid}/workspaces/{workspace_uuid}/tokens/generate`
1186
1254
 
1187
1255
  For complete API documentation, visit: [Redacto API Documentation](https://staging.api.redacto.io/consent/docs)
1188
1256
 
@@ -682,6 +682,66 @@ var useMediaQuery = (query) => {
682
682
  return matches;
683
683
  };
684
684
 
685
+ // src/shared/endpoints.ts
686
+ var CONSENT_PATH = "/consent";
687
+ var LEDGER_PATH = "/consent-ledger";
688
+ var ABSOLUTE_HTTP_URL = /^https?:\/\/(?:\[[0-9a-f:.]+\]|[^\s/?#@:[\]]+)(?::\d+)?(?:\/[^\s?#]*)?$/i;
689
+ var trimUrl = (value) => (value != null ? value : "").trim().replace(/\/+$/, "");
690
+ var isConsentServerUrl = (trimmed) => ABSOLUTE_HTTP_URL.test(trimmed) && trimmed.endsWith(CONSENT_PATH);
691
+ var isHostForm = (trimmed) => ABSOLUTE_HTTP_URL.test(trimmed) && !trimmed.endsWith(CONSENT_PATH);
692
+ function resolveEndpoints(baseUrl, ledgerBaseUrl) {
693
+ const trimmed = trimUrl(baseUrl);
694
+ if (!isHostForm(trimmed)) {
695
+ return { mode: "legacy", apiHost: void 0, baseUrl, ledgerBaseUrl };
696
+ }
697
+ const apiHost = trimmed.endsWith(LEDGER_PATH) ? trimmed.slice(0, -LEDGER_PATH.length) : trimmed;
698
+ return {
699
+ mode: "host",
700
+ apiHost,
701
+ baseUrl: `${apiHost}${CONSENT_PATH}`,
702
+ ledgerBaseUrl: `${apiHost}${LEDGER_PATH}`
703
+ };
704
+ }
705
+ var ENDPOINT_WARNINGS = {
706
+ missingBaseUrl: "[Redacto] baseUrl is not set, so the SDK's built-in production default is used. Pass baseUrl: your API host.",
707
+ consentServerBaseUrl: "[Redacto] baseUrl is the consent server URL (ending in /consent), which is deprecated. Pass the API host instead; the SDK derives the consent server and ledger URLs from it.",
708
+ ledgerBaseUrl: "[Redacto] ledgerBaseUrl is deprecated. Pass the Redacto API host as baseUrl instead; the SDK then reaches the consent server and the ledger under it.",
709
+ ledgerBaseUrlIgnored: "[Redacto] ledgerBaseUrl is ignored because baseUrl is the API host; the SDK reaches the ledger under that host. Remove ledgerBaseUrl.",
710
+ slugIgnored: "[Redacto] slug is deprecated and ignored. The Privacy Center reads the organisation from the access token, or from organisationUuid and workspaceUuid. Remove slug."
711
+ };
712
+ var issuedWarnings = /* @__PURE__ */ new Set();
713
+ var warnOnce = (warning) => {
714
+ if (issuedWarnings.has(warning)) {
715
+ return;
716
+ }
717
+ issuedWarnings.add(warning);
718
+ console.warn(ENDPOINT_WARNINGS[warning]);
719
+ };
720
+ var warnEndpointUsage = (baseUrl, ledgerBaseUrl, { hasBuiltInDefault }) => {
721
+ if (!baseUrl) {
722
+ if (hasBuiltInDefault) {
723
+ warnOnce("missingBaseUrl");
724
+ }
725
+ } else if (isConsentServerUrl(trimUrl(baseUrl))) {
726
+ warnOnce("consentServerBaseUrl");
727
+ }
728
+ if (trimUrl(ledgerBaseUrl)) {
729
+ warnOnce(isHostForm(trimUrl(baseUrl)) ? "ledgerBaseUrlIgnored" : "ledgerBaseUrl");
730
+ }
731
+ };
732
+ var warnSlugDeprecated = () => {
733
+ warnOnce("slugIgnored");
734
+ };
735
+
736
+ // src/shared/useResolvedEndpoints.ts
737
+ import { useMemo } from "react";
738
+ var useResolvedEndpoints = (baseUrl, ledgerBaseUrl, { warn = true, hasBuiltInDefault = true } = {}) => useMemo(() => {
739
+ if (warn) {
740
+ warnEndpointUsage(baseUrl, ledgerBaseUrl, { hasBuiltInDefault });
741
+ }
742
+ return resolveEndpoints(baseUrl, ledgerBaseUrl);
743
+ }, [baseUrl, ledgerBaseUrl, warn, hasBuiltInDefault]);
744
+
685
745
  // src/shared/sandbox.ts
686
746
  var SANDBOX_TOKEN_HEADER = "X-Consent-Token";
687
747
 
@@ -757,5 +817,9 @@ export {
757
817
  configureNoticeFonts,
758
818
  loadNoticeWebfont,
759
819
  useMediaQuery,
760
- applyScopedCustomCss
820
+ applyScopedCustomCss,
821
+ resolveEndpoints,
822
+ warnEndpointUsage,
823
+ warnSlugDeprecated,
824
+ useResolvedEndpoints
761
825
  };
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import React__default from 'react';
3
- import { A as AppearanceStyle, N as NoticeControlStyle, a as NoticeMobileLayout, b as NoticeDesktopPosition, c as NoticeBackdrop, d as NoticePhoneFooter, e as NoticeTextScale, f as NoticeAppearance } from './types-Bwtzvz4W.mjs';
3
+ import { A as AppearanceStyle, N as NoticeControlStyle, a as NoticeMobileLayout, b as NoticeDesktopPosition, c as NoticeBackdrop, d as NoticePhoneFooter, e as NoticeTextScale, f as NoticeAppearance } from './types-B8qroG0j.mjs';
4
4
  import { f as NoticeFontOptions } from './types-xaCyZUfo.mjs';
5
5
 
6
6
  /**
@@ -341,6 +341,11 @@ type ConsentFlowState = "age-check" | "guardian-details" | "digilocker-pending"
341
341
  */
342
342
  type DigiLockerCallbackProps = {
343
343
  accessToken: string;
344
+ /**
345
+ * API host, e.g. https://api.redacto.io (recommended). The consent server
346
+ * URL (…/consent) still works but is deprecated. Defaults to the URL the
347
+ * notice stored before redirecting.
348
+ */
344
349
  baseUrl?: string;
345
350
  onSuccess?: (verificationReference: string) => void;
346
351
  onError?: (error: Error, errorCode?: GuardianVerificationErrorCode) => void;
@@ -376,7 +381,17 @@ type Props$1 = Readonly<{
376
381
  organisationUuid?: string;
377
382
  /** Sandbox workspace UUID (replaces the JWT-decoded workspace in sandbox mode). */
378
383
  workspaceUuid?: string;
384
+ /**
385
+ * API host, e.g. https://api.redacto.io (recommended). The consent server
386
+ * URL (…/consent) still works but is deprecated.
387
+ * When omitted, the SDK's built-in production default is used.
388
+ */
379
389
  baseUrl?: string;
390
+ /**
391
+ * @deprecated Read only when `baseUrl` is the consent server URL
392
+ * (`…/consent`) or omitted, as in earlier releases. Ignored when `baseUrl`
393
+ * is the API host.
394
+ */
380
395
  ledgerBaseUrl?: string;
381
396
  /**
382
397
  * Optional code-side styling. The notice's look is set in the Redacto
@@ -452,7 +467,17 @@ type Props = Readonly<{
452
467
  notice_uuid: string;
453
468
  accessToken?: string;
454
469
  refreshToken?: string;
470
+ /**
471
+ * API host, e.g. https://api.redacto.io (recommended). The consent server
472
+ * URL (…/consent) still works but is deprecated.
473
+ * When omitted, the SDK's built-in production default is used.
474
+ */
455
475
  baseUrl?: string;
476
+ /**
477
+ * @deprecated Read only when `baseUrl` is the consent server URL
478
+ * (`…/consent`) or omitted, as in earlier releases. Ignored when `baseUrl`
479
+ * is the API host.
480
+ */
456
481
  ledgerBaseUrl?: string;
457
482
  /**
458
483
  * Optional code-side styling; overrides the appearance set in the Redacto
@@ -468,7 +493,7 @@ type Props = Readonly<{
468
493
  }>;
469
494
 
470
495
  declare const RedactoConsentInline: React.MemoExoticComponent<{
471
- ({ org_uuid, workspace_uuid, notice_uuid, accessToken, baseUrl, ledgerBaseUrl, language, onAccept, onError, onValidationChange, settings, applicationId, }: Props): React.JSX.Element | null;
496
+ ({ org_uuid, workspace_uuid, notice_uuid, accessToken, baseUrl: baseUrlProp, ledgerBaseUrl: ledgerBaseUrlProp, language, onAccept, onError, onValidationChange, settings, applicationId, }: Props): React.JSX.Element | null;
472
497
  displayName: string;
473
498
  }>;
474
499
 
@@ -484,9 +509,18 @@ type RedactoNoticeAssistedProps = {
484
509
  workspaceUuid: string;
485
510
  /** Notice UUID to fetch and render. */
486
511
  noticeUuid: string;
487
- /** API base URL (defaults to the production consent API). */
512
+ /**
513
+ * API host, e.g. https://api.redacto.io (recommended). The consent server
514
+ * URL (…/consent) still works but is deprecated.
515
+ * When omitted, the SDK's built-in production default is used.
516
+ */
488
517
  baseUrl?: string;
489
- /** Go ledger base URL — routes the consent write to the ledger; omit to use the legacy consent server. */
518
+ /**
519
+ * @deprecated Read only when `baseUrl` is the consent server URL
520
+ * (`…/consent`) or omitted, as in earlier releases. Ignored when `baseUrl`
521
+ * is the API host. With the consent server URL, it routes the consent write to
522
+ * the ledger; omit it there to use the legacy consent server.
523
+ */
490
524
  ledgerBaseUrl?: string;
491
525
  /** Called when the agent/customer declines (host should unmount the modal). */
492
526
  onDecline?: () => void;
@@ -514,7 +548,7 @@ type RedactoNoticeAssistedProps = {
514
548
  * submit, `onComplete` fires immediately with no confirmation screen (mirroring
515
549
  * RedactoNoticeConsent's `onAccept`). Steps: `notice` → `verify` (with `otpSent`).
516
550
  */
517
- declare const RedactoNoticeAssisted: ({ organisationUuid, workspaceUuid, noticeUuid, baseUrl, ledgerBaseUrl, onDecline, onComplete, settings, }: RedactoNoticeAssistedProps) => React.JSX.Element;
551
+ declare const RedactoNoticeAssisted: ({ organisationUuid, workspaceUuid, noticeUuid, baseUrl: baseUrlProp, ledgerBaseUrl: ledgerBaseUrlProp, onDecline, onComplete, settings, }: RedactoNoticeAssistedProps) => React.JSX.Element;
518
552
 
519
553
  /**
520
554
  * The notice exactly as the SDK draws it, from content the Redacto console
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import React__default from 'react';
3
- import { A as AppearanceStyle, N as NoticeControlStyle, a as NoticeMobileLayout, b as NoticeDesktopPosition, c as NoticeBackdrop, d as NoticePhoneFooter, e as NoticeTextScale, f as NoticeAppearance } from './types-Bwtzvz4W.js';
3
+ import { A as AppearanceStyle, N as NoticeControlStyle, a as NoticeMobileLayout, b as NoticeDesktopPosition, c as NoticeBackdrop, d as NoticePhoneFooter, e as NoticeTextScale, f as NoticeAppearance } from './types-B8qroG0j.js';
4
4
  import { f as NoticeFontOptions } from './types-xaCyZUfo.js';
5
5
 
6
6
  /**
@@ -341,6 +341,11 @@ type ConsentFlowState = "age-check" | "guardian-details" | "digilocker-pending"
341
341
  */
342
342
  type DigiLockerCallbackProps = {
343
343
  accessToken: string;
344
+ /**
345
+ * API host, e.g. https://api.redacto.io (recommended). The consent server
346
+ * URL (…/consent) still works but is deprecated. Defaults to the URL the
347
+ * notice stored before redirecting.
348
+ */
344
349
  baseUrl?: string;
345
350
  onSuccess?: (verificationReference: string) => void;
346
351
  onError?: (error: Error, errorCode?: GuardianVerificationErrorCode) => void;
@@ -376,7 +381,17 @@ type Props$1 = Readonly<{
376
381
  organisationUuid?: string;
377
382
  /** Sandbox workspace UUID (replaces the JWT-decoded workspace in sandbox mode). */
378
383
  workspaceUuid?: string;
384
+ /**
385
+ * API host, e.g. https://api.redacto.io (recommended). The consent server
386
+ * URL (…/consent) still works but is deprecated.
387
+ * When omitted, the SDK's built-in production default is used.
388
+ */
379
389
  baseUrl?: string;
390
+ /**
391
+ * @deprecated Read only when `baseUrl` is the consent server URL
392
+ * (`…/consent`) or omitted, as in earlier releases. Ignored when `baseUrl`
393
+ * is the API host.
394
+ */
380
395
  ledgerBaseUrl?: string;
381
396
  /**
382
397
  * Optional code-side styling. The notice's look is set in the Redacto
@@ -452,7 +467,17 @@ type Props = Readonly<{
452
467
  notice_uuid: string;
453
468
  accessToken?: string;
454
469
  refreshToken?: string;
470
+ /**
471
+ * API host, e.g. https://api.redacto.io (recommended). The consent server
472
+ * URL (…/consent) still works but is deprecated.
473
+ * When omitted, the SDK's built-in production default is used.
474
+ */
455
475
  baseUrl?: string;
476
+ /**
477
+ * @deprecated Read only when `baseUrl` is the consent server URL
478
+ * (`…/consent`) or omitted, as in earlier releases. Ignored when `baseUrl`
479
+ * is the API host.
480
+ */
456
481
  ledgerBaseUrl?: string;
457
482
  /**
458
483
  * Optional code-side styling; overrides the appearance set in the Redacto
@@ -468,7 +493,7 @@ type Props = Readonly<{
468
493
  }>;
469
494
 
470
495
  declare const RedactoConsentInline: React.MemoExoticComponent<{
471
- ({ org_uuid, workspace_uuid, notice_uuid, accessToken, baseUrl, ledgerBaseUrl, language, onAccept, onError, onValidationChange, settings, applicationId, }: Props): React.JSX.Element | null;
496
+ ({ org_uuid, workspace_uuid, notice_uuid, accessToken, baseUrl: baseUrlProp, ledgerBaseUrl: ledgerBaseUrlProp, language, onAccept, onError, onValidationChange, settings, applicationId, }: Props): React.JSX.Element | null;
472
497
  displayName: string;
473
498
  }>;
474
499
 
@@ -484,9 +509,18 @@ type RedactoNoticeAssistedProps = {
484
509
  workspaceUuid: string;
485
510
  /** Notice UUID to fetch and render. */
486
511
  noticeUuid: string;
487
- /** API base URL (defaults to the production consent API). */
512
+ /**
513
+ * API host, e.g. https://api.redacto.io (recommended). The consent server
514
+ * URL (…/consent) still works but is deprecated.
515
+ * When omitted, the SDK's built-in production default is used.
516
+ */
488
517
  baseUrl?: string;
489
- /** Go ledger base URL — routes the consent write to the ledger; omit to use the legacy consent server. */
518
+ /**
519
+ * @deprecated Read only when `baseUrl` is the consent server URL
520
+ * (`…/consent`) or omitted, as in earlier releases. Ignored when `baseUrl`
521
+ * is the API host. With the consent server URL, it routes the consent write to
522
+ * the ledger; omit it there to use the legacy consent server.
523
+ */
490
524
  ledgerBaseUrl?: string;
491
525
  /** Called when the agent/customer declines (host should unmount the modal). */
492
526
  onDecline?: () => void;
@@ -514,7 +548,7 @@ type RedactoNoticeAssistedProps = {
514
548
  * submit, `onComplete` fires immediately with no confirmation screen (mirroring
515
549
  * RedactoNoticeConsent's `onAccept`). Steps: `notice` → `verify` (with `otpSent`).
516
550
  */
517
- declare const RedactoNoticeAssisted: ({ organisationUuid, workspaceUuid, noticeUuid, baseUrl, ledgerBaseUrl, onDecline, onComplete, settings, }: RedactoNoticeAssistedProps) => React.JSX.Element;
551
+ declare const RedactoNoticeAssisted: ({ organisationUuid, workspaceUuid, noticeUuid, baseUrl: baseUrlProp, ledgerBaseUrl: ledgerBaseUrlProp, onDecline, onComplete, settings, }: RedactoNoticeAssistedProps) => React.JSX.Element;
518
552
 
519
553
  /**
520
554
  * The notice exactly as the SDK draws it, from content the Redacto console