redacto_consent_sdk 2.0.0
redacto_consent_sdk: ^2.0.0 copied to clipboard
Flutter SDK for integrating Redacto consent notices.
Changelog #
2.0.0 #
Stable M3 release, versioned alongside @redacto.io/consent-sdk-js 1.0.0, @redacto.io/consent-sdk-react 10.0.0 and @redacto.io/consent-sdk-react-native 5.0.0. Identical in content to 2.0.0-beta.4; the full set of changes since 1.0.1 is listed under the 2.0.0-beta.* entries below. Highlights:
- Go consent ledger support (
ledgerBaseUrl) across the notice widgets and the Privacy Center — consent writes, the notice read, user-consents, receipts and revoke/regrant/renew. OmittingledgerBaseUrlkeeps every call on the legacy Python endpoints. - Privacy Center gains the Notification Hub, the shared-contact profile picker, a terminal session-expired state, and a refresh-token breaker that stops re-submitting a dead token.
- DSAR request form fixes: purposes sourced from user-consents, product-anchored cases, supporting-document upload, erasure auto-revoke, and an access time-period picker.
- Consent events (notice and Privacy Center) record the language the notice was displayed in.
- Sandbox mode for
RedactoNoticeConsentandRedactoPrivacyCentervia a pasted static token. - Removed the unsupported Bhojpuri (
bho) locale.
2.0.0-beta.4 #
Parity fixes against consent-sdk-react for the erasure / notice flows (#584).
- Erasure auto-revoke on fulfilment: DSAR erasure now shows the revoke-consent confirmation modal and sends
revoke_consent_on_fulfilment(includingfalse), matching React / RN. Previously only the translation strings existed; the feature was never wired. - Access requests expose a time-period picker (today / last 7 days / last 30 days / last 3 months) instead of hardcoding
time_period: 30. - Notice banners consume the inline reconsent overlay from the notice read and drop the redundant
check-consentround-trip that could wipe purpose selections. - A failed notice read shows a fetch-error view with Refresh / close instead of a blank white card that blocked dismissal under
blockUI.
2.0.0-beta.3 #
The Privacy Center resolves the acting contact from the JWT's identifier claims instead of an opaque row id.
- Revoke / regrant / renew in
RedactoPrivacyCenterno longer fails against the Python backend with 403contact_mismatch. The contact was resolved from a chain that consulteduser_uuid/subahead ofuser_data, andTokenService.generate_tokensnever mints a top-levelcontact/primary_email/emailclaim but always mintsuser_uuid— so every real token resolved to a uuid, which Python's/manage-consentthen rejected when it cross-checked the body'scontactagainst the subject it derives fromuser_dataalone. The Go ledger sends nocontactand resolves the principal from the token, which is why the same action worked there and masked the bug. Resolution is nowcontact → primary_email → user_data.primary_email → user_data.primary_mobile → user_data.org_user_id, portingresolveContactFromJwtfrom@redacto.io/consent-sdk-react; blank and whitespace-only claims are skipped rather than winning the chain. This also fixes mobile-only logins, which previously had no usable contact, and stops the uuid leaking into the account label in the nav drawer. Under a shared contact both sibling principals resolve the shared email rather thanorg_user_id— the server derives its subject the same way, and isolation comes fromextract_org_user_id_from_jwt(), which the client never supplies.
2.0.0-beta.2 #
The notice read is fetched from the Go consent ledger, and the Privacy Center / DSAR parity gaps opened by the ledger cutover are closed.
- The notice read is now served by the Go ledger whenever a
ledgerBaseUrlis configured, in bothRedactoNoticeConsentandRedactoNoticeConsentInline— mirroring@redacto.io/consent-sdk-react(CON-I1030), which had routed only its modal. Previously the read always went tobaseUrl, so a deployment whose tokens are minted on the ledger (the demo backend does this wheneverLEDGER_BASE_URLis set) got a 401 from the consent server, which does not accept ledger-issued JWTs — the notice modal then rendered with no content.FetchConsentContentParamsandFetchInlineConsentContentParamsgain an optionalledgerBaseUrl; resolution isledgerBaseUrl ?? baseUrl ?? defaultwith empty strings counting as unset, matching the||fallback in the JS/React/RN SDKs. - Routing lives in
ConsentApirather than at each call site, so every caller of the two reads gets it, and the exceptions are stated once: the magic-link flow (applicationId/specific_uuid) and sandbox sessions stay on the consent server, which the ledger read supports for neither, and the tokenless inline read stays there too because the ledger does not implementnotices/get-notice/{uuid}. Guardian verification (guardian-info,guardian/initiate-verification,guardian/verify-status) has no ledger equivalent and is unchanged on the consent server. OmittingledgerBaseUrlkeeps every call on the legacy Python endpoints, as before. ConsentApi.fetchConsentContent's response cache now keys on the resolved base URL, so a ledger read and a consent-server read for the same principal and notice can no longer be served from each other's entry.- Declining a notice does not record a consent event. The port of
@redacto.io/consent-sdk-reactCON-I1670 landed here ahead of the React change itself, so this SDK briefly wrote an explicit "no" while react, react-native and js did not. Reverted to a plain close so all four SDKs adopt the behaviour together when the React PR ships; the API layer'sdeclinedsupport is unchanged and still covered by tests. - New: the shared-contact profile picker, previously absent from this SDK. When a signed-in email or mobile maps to more than one data principal,
RedactoPrivacyCenternow asks which profile to view instead of silently showing whichever one the server resolved.PrivacyCenterApigainslistIdentities,selectPrincipalandadoptTokens, withIdentityCandidate/SelectPrincipalResponsemodels;RedactoJwtPayloadexposesorgUserIdfrom the token'suser_data. The gate resolves before any consent read, so nothing is ever fetched against a token not yet scoped to a principal, and it degrades to the normal view on any failure — a backend without the endpoint keeps working. Each row leads withorg_user_id, the only value that distinguishes principals sharing a contact, falling back to email → mobile → uuid. A "switch profile" action appears in the navbar only when more than one profile exists. PortsSelectUserGate/SelectUserfrom@redacto.io/consent-sdk-react(CON-I1221 + #522); the session pin is held in widget state rather than sessionStorage, which has no Flutter equivalent, so a routine token refresh does not re-open the picker. PrivacyCenterApino longer re-submits a dead refresh token on every call. It had single-flight dedup but no memory of failure, so once a refresh token was expired or invalid, each authenticated call and each poller tick re-attempted it. A refresh that fails with 400/401/403/422 now trips a breaker keyed by the token value — one attempt, then no network call at all until a different token appears, so re-authentication always recovers. Transient failures (5xx/408/429, network, timeout) instead open a backoff window doubling from 30s to a 5m ceiling, leaving the token usable.isRefreshBlockedis exposed so pollers can skip doomed work; the notification bell and the case-messages poll both consult it. Ports the breaker added to@redacto.io/consent-sdk-reactafter the 2026-06-22 incident.RedactoPrivacyCenternow has a terminal session-expired state. A refresh that fails terminally — or a missing refresh token — fires the newPrivacyCenterApi.onSessionExpired, which gates all fetching behind a dedicated "Your session has expired" screen instead of letting each widget 401 independently and render empty or stale content. Exit is a deliberate user action via the existingonBackprop; the React reference dropped its automatic redirect for the same reason.sessionExpiredTitle/sessionExpiredDescriptionwere sourced from the React SDK's own locales, which carry all 23 languages.- New: the Notification Hub, previously absent from this SDK.
PrivacyCenterApigainsgetNotifications,getNotificationSummary,markNotificationRead,markAllNotificationsReadandacknowledgeNotification, withPrivacyNotification,NotificationCta,NotificationSummaryandNotificationListResponsemodels.RedactoPrivacyCentershows a bell with an unread badge in the navbar (polling every 30s, matching the ReactPOLL_INTERVAL) and a newPrivacyCenterPage.notificationslisting summary counts, category filter tabs (all / consent / requests / system), paginated rows and mark-all-read. Notification CTAs are honoured: anacknowledgeCTA records the acknowledgement server-side, and alinkCTA marks the notification read and opens a case-details URL in place. PortsNotificationHubfrom@redacto.io/consent-sdk-react; the bell opens the list page directly rather than a hover dropdown, which has no mobile equivalent. - Regenerated
pc_translations.dartfrom the React Native locale sources, which the checked-in file had drifted from — every locale gains 84 keys (310 → 415 for English). English was missing the entire Notification Hub string set (notificationHub,unread,actionNeeded,markAllAsRead,justNow,minutesAgo, … 23 keys) that all 22 other locales already had, so the hub would have rendered untranslated for English users. Five keys the previous file carried but the RN source does not (paginationRange,noNotificationsYet,viewAllNotifications,loadingNotifications,refreshNotifications) moved intotool/pc_locale_supplement.json, with English values added, so regeneration no longer drops them. No existing translation changed. - Consent events now record the language the notice was displayed in.
submit-consentnever carried alanguage, so a consent given in Dogri or Bodo was stored against the notice's default and surfaced as English in Consent Records.SubmitConsentEventParamstakes an optionallanguage(omitted from the payload when null, so the backend keeps its default), the notice widget passestoBcp47Code(selectedLanguage)on both accept and decline, and a newtoBcp47Codemaps the display names the notice serves — English plus the 22 languages in the 8th Schedule — to BCP-47, portinglanguage-codes.tsfrom@redacto.io/consent-sdk-react. - Withdraw / regrant / renew in
RedactoPrivacyCenterrecords the selected language too.PrivacyCenterApi.manageConsenttakes an optionallanguageand includes it in both the ledger partial submit-consent body and the legacy manage-consent body; the consent manager passeslangParam, which is null for the default language so the field is omitted. Mirrors the same fix in@redacto.io/consent-sdk-react(#528). - A DECLINED purpose is re-grantable in the Privacy Center consent manager. Its Modify button was hard-disabled and the modify modal offered no action for that status, which left a declined record permanently stuck — untenable now that declines are actually written. It re-grants exactly like a withdrawal (a partial submit-consent re-selecting the purpose), so no backend change is involved.
- Cases raised from the DSAR request form now carry a product anchor, so the case queue shows the product name instead of leaving it blank. The queue derives
product_nameentirely from the case'sproduct_uuid(hydrate_product_names_on_cases: "cases withoutproduct_uuidgetproduct_name=None"), and the form never sent one.FormPurposenow carriesproductUuid/productName/nominatorUuidthrough from user-consents, andUserDataRequestgained optionalproduct_uuidanddata_principal_uuid, both omitted from the payload rather than sent null so the backend still reads an unanchored case as org-level. Anchoring applies only to the product-scoped request types (access / erasure / correction), matchingPRODUCT_SCOPED_REQUEST_TYPESin@redacto.io/consent-sdk-react; nomination and grievance stay org-level. Where React anchors to the group picked in its product-selection step, this form has none, so the anchor is derived from the selected purposes: purposes spanning two products, and purposes from Python's flatform/data(which carries no product), submit org-level rather than attributing the case to an arbitrary product. - The DSAR request form no longer throws
ListTile background color or ink splashes may be invisiblein debug builds. The request-details sections are built fromCheckboxListTiles, which paint their ink splashes on the nearestMaterialancestor; the opaque accordion and form-cardContainers sat between the two, so the splashes rendered behind them. The section content is now wrapped in aMaterialType.transparencyMaterial, which restores the splashes without altering the accordion's background. - The DSAR request form's request-details picker is now sourced from user-consents instead of Python's
form/data, which stopped emittingpurposesafter the consent cutover — leaving the access/erasure/correction sections permanently empty ("no purposes available") once a ledger was configured.getUserConsentsserves the same grouped payload from either backend, so the overlay works with or without a ledger. The form is left untouched when the read fails or yields nothing usable, so an empty result never overwrites purposesform/datadid supply, and grievance/nomination (which do not depend on purposes) are unaffected. MirrorswithUserConsentPickerGroupsin@redacto.io/consent-sdk-react, flattened because this form has no product-selection step. NewformPurposesFromConsentGroupshelper, andformPickerGroupLimit(100, matching the React constant). - Supporting-document upload on the DSAR form no longer fails with a 422 (
organization_uuid,uuid,is_public,allow_ai_processing—Field required). The shared multipart helper sent{"metadata": null}for both upload endpoints, which is what the case-document endpoint accepts, but the privacy-center form endpoint validates a full payload.uploadFormDocumentnow sendsorganization_uuid,space, a generateduuid,is_public,allow_ai_processingand theprivacymetadata block, matching the React reference;uploadCaseDocumentis unchanged.uploadFormDocumenttakes a new requiredformUuid(theuuidfromgetFormData) which scopes the stored document. - Revoke/regrant/renew in
RedactoPrivacyCenterno longer fails withnotice_uuid is required to manage consent via the ledger. The ledger'suser-consentsresponse groups rows by product and carriesnotice_uuidon each nested purpose;UserConsentandPurposeItemboth parsed it, but the two consent-manager group mappings inconsent_manager_utils.dartrebuilt each row field-by-field and omitted it, so every ledger-served row reached the UI withnoticeUuid: nulland ledger-mode manage-consent rejected the request. Both mappings now thread it through, as the post-action optimistic row rebuild already did.@redacto.io/consent-sdk-reactthrows the same error from the same guard but never trips it, because it carries the raw row object rather than reconstructing it.
2.0.0-beta.1 #
- Declining a notice does not record a consent event. The port of
@redacto.io/consent-sdk-reactCON-I1670 landed here ahead of the React change itself, so this SDK briefly wrote an explicit "no" while react, react-native and js did not. Reverted to a plain close so all four SDKs adopt the behaviour together when the React PR ships; the API layer'sdeclinedsupport is unchanged and still covered by tests. - New: the shared-contact profile picker, previously absent from this SDK. When a signed-in email or mobile maps to more than one data principal,
RedactoPrivacyCenternow asks which profile to view instead of silently showing whichever one the server resolved.PrivacyCenterApigainslistIdentities,selectPrincipalandadoptTokens, withIdentityCandidate/SelectPrincipalResponsemodels;RedactoJwtPayloadexposesorgUserIdfrom the token'suser_data. The gate resolves before any consent read, so nothing is ever fetched against a token not yet scoped to a principal, and it degrades to the normal view on any failure — a backend without the endpoint keeps working. Each row leads withorg_user_id, the only value that distinguishes principals sharing a contact, falling back to email → mobile → uuid. A "switch profile" action appears in the navbar only when more than one profile exists. PortsSelectUserGate/SelectUserfrom@redacto.io/consent-sdk-react(CON-I1221 + #522); the session pin is held in widget state rather than sessionStorage, which has no Flutter equivalent, so a routine token refresh does not re-open the picker. PrivacyCenterApino longer re-submits a dead refresh token on every call. It had single-flight dedup but no memory of failure, so once a refresh token was expired or invalid, each authenticated call and each poller tick re-attempted it. A refresh that fails with 400/401/403/422 now trips a breaker keyed by the token value — one attempt, then no network call at all until a different token appears, so re-authentication always recovers. Transient failures (5xx/408/429, network, timeout) instead open a backoff window doubling from 30s to a 5m ceiling, leaving the token usable.isRefreshBlockedis exposed so pollers can skip doomed work; the notification bell and the case-messages poll both consult it. Ports the breaker added to@redacto.io/consent-sdk-reactafter the 2026-06-22 incident.RedactoPrivacyCenternow has a terminal session-expired state. A refresh that fails terminally — or a missing refresh token — fires the newPrivacyCenterApi.onSessionExpired, which gates all fetching behind a dedicated "Your session has expired" screen instead of letting each widget 401 independently and render empty or stale content. Exit is a deliberate user action via the existingonBackprop; the React reference dropped its automatic redirect for the same reason.sessionExpiredTitle/sessionExpiredDescriptionwere sourced from the React SDK's own locales, which carry all 23 languages.- New: the Notification Hub, previously absent from this SDK.
PrivacyCenterApigainsgetNotifications,getNotificationSummary,markNotificationRead,markAllNotificationsReadandacknowledgeNotification, withPrivacyNotification,NotificationCta,NotificationSummaryandNotificationListResponsemodels.RedactoPrivacyCentershows a bell with an unread badge in the navbar (polling every 30s, matching the ReactPOLL_INTERVAL) and a newPrivacyCenterPage.notificationslisting summary counts, category filter tabs (all / consent / requests / system), paginated rows and mark-all-read. Notification CTAs are honoured: anacknowledgeCTA records the acknowledgement server-side, and alinkCTA marks the notification read and opens a case-details URL in place. PortsNotificationHubfrom@redacto.io/consent-sdk-react; the bell opens the list page directly rather than a hover dropdown, which has no mobile equivalent. - Regenerated
pc_translations.dartfrom the React Native locale sources, which the checked-in file had drifted from — every locale gains 84 keys (310 → 415 for English). English was missing the entire Notification Hub string set (notificationHub,unread,actionNeeded,markAllAsRead,justNow,minutesAgo, … 23 keys) that all 22 other locales already had, so the hub would have rendered untranslated for English users. Five keys the previous file carried but the RN source does not (paginationRange,noNotificationsYet,viewAllNotifications,loadingNotifications,refreshNotifications) moved intotool/pc_locale_supplement.json, with English values added, so regeneration no longer drops them. No existing translation changed. - Consent events now record the language the notice was displayed in.
submit-consentnever carried alanguage, so a consent given in Dogri or Bodo was stored against the notice's default and surfaced as English in Consent Records.SubmitConsentEventParamstakes an optionallanguage(omitted from the payload when null, so the backend keeps its default), the notice widget passestoBcp47Code(selectedLanguage)on both accept and decline, and a newtoBcp47Codemaps the display names the notice serves — English plus the 22 languages in the 8th Schedule — to BCP-47, portinglanguage-codes.tsfrom@redacto.io/consent-sdk-react. - Withdraw / regrant / renew in
RedactoPrivacyCenterrecords the selected language too.PrivacyCenterApi.manageConsenttakes an optionallanguageand includes it in both the ledger partial submit-consent body and the legacy manage-consent body; the consent manager passeslangParam, which is null for the default language so the field is omitted. Mirrors the same fix in@redacto.io/consent-sdk-react(#528). - A DECLINED purpose is re-grantable in the Privacy Center consent manager. Its Modify button was hard-disabled and the modify modal offered no action for that status, which left a declined record permanently stuck — untenable now that declines are actually written. It re-grants exactly like a withdrawal (a partial submit-consent re-selecting the purpose), so no backend change is involved.
- Cases raised from the DSAR request form now carry a product anchor, so the case queue shows the product name instead of leaving it blank. The queue derives
product_nameentirely from the case'sproduct_uuid(hydrate_product_names_on_cases: "cases withoutproduct_uuidgetproduct_name=None"), and the form never sent one.FormPurposenow carriesproductUuid/productName/nominatorUuidthrough from user-consents, andUserDataRequestgained optionalproduct_uuidanddata_principal_uuid, both omitted from the payload rather than sent null so the backend still reads an unanchored case as org-level. Anchoring applies only to the product-scoped request types (access / erasure / correction), matchingPRODUCT_SCOPED_REQUEST_TYPESin@redacto.io/consent-sdk-react; nomination and grievance stay org-level. Where React anchors to the group picked in its product-selection step, this form has none, so the anchor is derived from the selected purposes: purposes spanning two products, and purposes from Python's flatform/data(which carries no product), submit org-level rather than attributing the case to an arbitrary product. - The DSAR request form no longer throws
ListTile background color or ink splashes may be invisiblein debug builds. The request-details sections are built fromCheckboxListTiles, which paint their ink splashes on the nearestMaterialancestor; the opaque accordion and form-cardContainers sat between the two, so the splashes rendered behind them. The section content is now wrapped in aMaterialType.transparencyMaterial, which restores the splashes without altering the accordion's background. - The DSAR request form's request-details picker is now sourced from user-consents instead of Python's
form/data, which stopped emittingpurposesafter the consent cutover — leaving the access/erasure/correction sections permanently empty ("no purposes available") once a ledger was configured.getUserConsentsserves the same grouped payload from either backend, so the overlay works with or without a ledger. The form is left untouched when the read fails or yields nothing usable, so an empty result never overwrites purposesform/datadid supply, and grievance/nomination (which do not depend on purposes) are unaffected. MirrorswithUserConsentPickerGroupsin@redacto.io/consent-sdk-react, flattened because this form has no product-selection step. NewformPurposesFromConsentGroupshelper, andformPickerGroupLimit(100, matching the React constant). - Supporting-document upload on the DSAR form no longer fails with a 422 (
organization_uuid,uuid,is_public,allow_ai_processing—Field required). The shared multipart helper sent{"metadata": null}for both upload endpoints, which is what the case-document endpoint accepts, but the privacy-center form endpoint validates a full payload.uploadFormDocumentnow sendsorganization_uuid,space, a generateduuid,is_public,allow_ai_processingand theprivacymetadata block, matching the React reference;uploadCaseDocumentis unchanged.uploadFormDocumenttakes a new requiredformUuid(theuuidfromgetFormData) which scopes the stored document. - Revoke/regrant/renew in
RedactoPrivacyCenterno longer fails withnotice_uuid is required to manage consent via the ledger. The ledger'suser-consentsresponse groups rows by product and carriesnotice_uuidon each nested purpose;UserConsentandPurposeItemboth parsed it, but the two consent-manager group mappings inconsent_manager_utils.dartrebuilt each row field-by-field and omitted it, so every ledger-served row reached the UI withnoticeUuid: nulland ledger-mode manage-consent rejected the request. Both mappings now thread it through, as the post-action optimistic row rebuild already did.@redacto.io/consent-sdk-reactthrows the same error from the same guard but never trips it, because it carries the raw row object rather than reconstructing it. - The notice read is now served by the Go ledger whenever a
ledgerBaseUrlis configured, in bothRedactoNoticeConsentandRedactoNoticeConsentInline— mirroring@redacto.io/consent-sdk-react(CON-I1030), which had routed only its modal. Previously the read always went tobaseUrl, so a deployment whose tokens are minted on the ledger (the demo backend does this wheneverLEDGER_BASE_URLis set) got a 401 from the consent server, which does not accept ledger-issued JWTs — the notice modal then rendered with no content.FetchConsentContentParamsandFetchInlineConsentContentParamsgain an optionalledgerBaseUrl; resolution isledgerBaseUrl ?? baseUrl ?? defaultwith empty strings counting as unset, matching the||fallback in the JS/React/RN SDKs. - Routing lives in
ConsentApirather than at each call site, so every caller of the two reads gets it, and the exceptions are stated once: the magic-link flow (applicationId/specific_uuid) and sandbox sessions stay on the consent server, which the ledger read supports for neither, and the tokenless inline read stays there too because the ledger does not implementnotices/get-notice/{uuid}. Guardian verification (guardian-info,guardian/initiate-verification,guardian/verify-status) has no ledger equivalent and is unchanged on the consent server. OmittingledgerBaseUrlkeeps every call on the legacy Python endpoints, as before. ConsentApi.fetchConsentContent's response cache now keys on the resolved base URL, so a ledger read and a consent-server read for the same principal and notice can no longer be served from each other's entry.- Added sandbox mode to
RedactoNoticeConsentandRedactoPrivacyCenter, so a full consent PoC — notice → Privacy Center → DSAR — runs with a pasted static token and no backend token minting. Sandbox is activated by the newtokenparameter and takesorganisationUuid/workspaceUuidfrom parameters instead of decoding a JWT; the acting test identity isucic>email>mobile. The token is sent as the singleX-Consent-Tokenheader (noAuthorization: Bearer, no refresh, so a 401 fails fast), and the identity rides each request's own payload — query params (org_user_id/primary_email/primary_mobile) on reads, the JSON body on writes. The server records everything underenvironment=test, isolated from live records. Sandbox always talks to the consent server, soledgerBaseUrlhas no effect there. New public API:SandboxAuthParams,SandboxAuth,ResolvedRequestAuth. Additive — the JWT path is unchanged, andRedactoNoticeConsentInlinehas no sandbox mode (matching@redacto.io/consent-sdk-react). - The revoke confirmation dialog in
RedactoPrivacyCenternow shows the admin-authored, per-purposerevoke_warning_messageserved on each user-consents row, falling back to the localizedrevokeConsentWarningcopy when it is null, empty, or absent (older backends).UserConsentandPurposeItemgain a nullablerevokeWarningMessagefield, threaded through the consent-manager group mappings so it reaches the modal. Mirrors@redacto.io/consent-sdk-react; only the active/revoke branch is affected — regrant and renew warnings are unchanged. RedactoNoticeConsentInlinereads the notice from the authenticatednotices/{notice_uuid}endpoint whenever an access token is available, instead of the tokenlessnotices/get-notice/{notice_uuid}. Only the consent server serves the tokenless path, so pointingbaseUrlat the Go consent ledger failed with 404Resource not foundeven though the notice existed there — and the path is compiled into the SDK, so nobaseUrlchange could fix it.notices/{notice_uuid}is the endpointRedactoNoticeConsenthas always used: both backends serve it, and it returns the caller'spurpose_selections/reconsent_requiredoverlay plus 409CONSENT_ALREADY_PROVIDED.FetchInlineConsentContentParamstakes a new optionalaccessToken(empty counts as unset); without one the tokenless path is unchanged.RedactoNoticeConsentInlinere-reads the notice when the host rebuilds it with anaccessTokenand the first read was tokenless, so a token that arrives after mount switches to the authenticated endpoint. Previously the widget only ever loaded ininitState, leaving the unauthenticated content on screen. A later token change does not refetch, so in-progress selections are kept. The load is generation-guarded, so the superseded tokenless read cannot resolve last and overwrite the authenticated content or reset the selections;_hasAlreadyConsentedis cleared at the start of each load.
2.0.0-beta.0 #
M3 beta, versioned alongside @redacto.io/consent-sdk-js 1.0.0-beta.0, @redacto.io/consent-sdk-react 10.0.0-beta.5 and @redacto.io/consent-sdk-react-native 5.0.0-beta.0. This release supersedes 1.1.0, which was prepared but never published to pub.dev; its notes are folded in below.
- Removed the unsupported Bhojpuri (
bho) locale. - Added
ledgerBaseUrlsupport (Go consent ledger) across the SDK, mirroring consent-sdk-react:RedactoNoticeConsentroutes its consent write through the first non-empty ofledgerBaseUrl,baseUrl, default — empty strings count as unset, matching the||fallback in the JS/React/RN SDKs — and overlays prior-consent/reconsent state from the ledger'scheck-consent(Python's notice-validation overlay is empty after the consent cutover).RedactoNoticeConsentInlineproactively short-circuits already-consented principals via the ledger check and gates auto-submit until it settles — the ledger equivalent of the legacy Python 409CONSENT_ALREADY_PROVIDED.RedactoPrivacyCenter(andPrivacyCenterApi.configure) acceptledgerBaseUrland route user-consents, receipts list and receipt PDF (/receipts/{uuid}/download) to the ledger; revoke/regrant/renew is expressed as apartial: truesubmit-consent on the ledger.- New public API:
ConsentApi.checkNoticeConsentStatus,NoticeConsentStatusResponse,buildLedgerConsentOverlay.
- Fully backward compatible: when
ledgerBaseUrlis omitted, every call stays on the legacy Python endpoints and the reactive 409 path governs (pre-ledger behavior).
1.0.1 #
- Docs: expand the package README to document the full feature set shipped in 1.0.0 — Privacy Center (widget, parameters, headless API), notice parameter tables, styling, localization, and troubleshooting. No functional or API changes.
1.0.0 #
First stable release.
Added #
- Privacy Center: multi-page certified UI with a headless core (#258, #411).
- "My Receipt" consent receipts support (#390).
- Privacy Center "no data" empty state (#408).
Changed #
- Aligned the Flutter SDK feature set and UI/UX with the iOS SDK (#251).
- Aligned Consent Manager to the GET user-consents contract (#387).
Fixed #
- Keep revoked-consent purposes raisable in Privacy Center DSAR forms (#381).
0.1.0 #
- Initial Flutter SDK scaffold with modal and inline consent widgets.