@redacto.io/consent-sdk-react 10.0.0-beta.9 → 10.0.0
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/NOTICE.md +17 -0
- package/README.md +141 -3
- package/dist/chunk-FEGTW73Q.mjs +182 -0
- package/dist/fonts.d.mts +35 -0
- package/dist/fonts.d.ts +35 -0
- package/dist/fonts.js +183 -0
- package/dist/fonts.mjs +10 -0
- package/dist/index.d.mts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +724 -365
- package/dist/index.mjs +346 -201
- package/dist/montserrat.generated-NBTECYRW.mjs +22 -0
- package/dist/privacy-center.d.mts +0 -1
- package/dist/privacy-center.d.ts +0 -1
- package/dist/privacy-center.js +2 -66
- package/dist/privacy-center.mjs +2 -66
- package/dist/types-6Aj7faxL.d.mts +57 -0
- package/dist/types-6Aj7faxL.d.ts +57 -0
- package/package.json +10 -1
- package/.turbo/turbo-build.log +0 -22
- package/.turbo/turbo-test.log +0 -203
- package/.turbo/turbo-verify-pack.log +0 -6
- package/CHANGELOG.md +0 -353
- package/src/RedactoNoticeAssisted/RedactoNoticeAssisted.test.tsx +0 -934
- package/src/RedactoNoticeAssisted/RedactoNoticeAssisted.tsx +0 -2160
- package/src/RedactoNoticeAssisted/api/index.ts +0 -275
- package/src/RedactoNoticeAssisted/api/types.ts +0 -182
- package/src/RedactoNoticeAssisted/assets/redacto-logo.png +0 -0
- package/src/RedactoNoticeAssisted/constants.ts +0 -51
- package/src/RedactoNoticeAssisted/i18n.ts +0 -1408
- package/src/RedactoNoticeAssisted/index.ts +0 -1
- package/src/RedactoNoticeAssisted/injectStyles.ts +0 -251
- package/src/RedactoNoticeAssisted/styles.ts +0 -730
- package/src/RedactoNoticeAssisted/types.ts +0 -26
- package/src/RedactoNoticeAssisted/useMediaQuery.ts +0 -36
- package/src/RedactoNoticeConsent/RedactoNoticeConsent.test.tsx +0 -1152
- package/src/RedactoNoticeConsent/RedactoNoticeConsent.tsx +0 -4308
- package/src/RedactoNoticeConsent/api/index.ts +0 -542
- package/src/RedactoNoticeConsent/api/sandbox.ts +0 -150
- package/src/RedactoNoticeConsent/api/types.ts +0 -515
- package/src/RedactoNoticeConsent/assets/redacto-logo.png +0 -0
- package/src/RedactoNoticeConsent/components/DigiLockerCallback.tsx +0 -602
- package/src/RedactoNoticeConsent/components/index.ts +0 -7
- package/src/RedactoNoticeConsent/constants.ts +0 -20
- package/src/RedactoNoticeConsent/index.ts +0 -1
- package/src/RedactoNoticeConsent/injectStyles.ts +0 -151
- package/src/RedactoNoticeConsent/language-codes.ts +0 -95
- package/src/RedactoNoticeConsent/services/storage.ts +0 -122
- package/src/RedactoNoticeConsent/styles.ts +0 -409
- package/src/RedactoNoticeConsent/types.ts +0 -80
- package/src/RedactoNoticeConsent/useMediaQuery.ts +0 -36
- package/src/RedactoNoticeConsentInline/RedactoNoticeConsentInline.test.tsx +0 -369
- package/src/RedactoNoticeConsentInline/RedactoNoticeConsentInline.tsx +0 -687
- package/src/RedactoNoticeConsentInline/api/index.ts +0 -106
- package/src/RedactoNoticeConsentInline/api/types.ts +0 -183
- package/src/RedactoNoticeConsentInline/assets/redacto-logo.png +0 -0
- package/src/RedactoNoticeConsentInline/index.ts +0 -1
- package/src/RedactoNoticeConsentInline/injectStyles.ts +0 -40
- package/src/RedactoNoticeConsentInline/styles.ts +0 -397
- package/src/RedactoNoticeConsentInline/types.ts +0 -51
- package/src/RedactoNoticeConsentInline/useMediaQuery.ts +0 -36
- package/src/RedactoPrivacyCenter/NotificationsPage.tsx +0 -182
- package/src/RedactoPrivacyCenter/PrivacyCenterActivityPage.tsx +0 -19
- package/src/RedactoPrivacyCenter/PrivacyCenterCaseDetailsPage.tsx +0 -156
- package/src/RedactoPrivacyCenter/PrivacyCenterConsentManagerPage.tsx +0 -17
- package/src/RedactoPrivacyCenter/PrivacyCenterFormPage.tsx +0 -79
- package/src/RedactoPrivacyCenter/PrivacyCenterHomePage.tsx +0 -36
- package/src/RedactoPrivacyCenter/PrivacyCenterLayout.tsx +0 -177
- package/src/RedactoPrivacyCenter/PrivacyCenterMyReceiptPage.tsx +0 -26
- package/src/RedactoPrivacyCenter/RedactoPrivacyCenter.tsx +0 -93
- package/src/RedactoPrivacyCenter/api/actions.ts +0 -695
- package/src/RedactoPrivacyCenter/api/client.ts +0 -1003
- package/src/RedactoPrivacyCenter/api/config.ts +0 -33
- package/src/RedactoPrivacyCenter/api/fetcher.ts +0 -275
- package/src/RedactoPrivacyCenter/api/orgBranding.ts +0 -16
- package/src/RedactoPrivacyCenter/api/upload.ts +0 -93
- package/src/RedactoPrivacyCenter/assets/character.svg +0 -31
- package/src/RedactoPrivacyCenter/assets/fileAttach.svg +0 -9
- package/src/RedactoPrivacyCenter/assets/greenTick.svg +0 -4
- package/src/RedactoPrivacyCenter/assets/mail.svg +0 -3
- package/src/RedactoPrivacyCenter/assets/poweredByRedacto.svg +0 -9
- package/src/RedactoPrivacyCenter/assets/sentImg.svg +0 -9
- package/src/RedactoPrivacyCenter/assets/uploadFileIcon.svg +0 -9
- package/src/RedactoPrivacyCenter/components/ActivitiesList.tsx +0 -252
- package/src/RedactoPrivacyCenter/components/ActivityTimeline.tsx +0 -239
- package/src/RedactoPrivacyCenter/components/AppShell/AppShell.tsx +0 -268
- package/src/RedactoPrivacyCenter/components/AppShell/MobileNavDrawer.tsx +0 -218
- package/src/RedactoPrivacyCenter/components/AppShell/NavItem.tsx +0 -205
- package/src/RedactoPrivacyCenter/components/AppShell/PageHeader.tsx +0 -107
- package/src/RedactoPrivacyCenter/components/AppShell/SidebarNav.tsx +0 -100
- package/src/RedactoPrivacyCenter/components/AppShell/TopAppBar.tsx +0 -339
- package/src/RedactoPrivacyCenter/components/AppShell/UserMenu.tsx +0 -245
- package/src/RedactoPrivacyCenter/components/AppShell/hooks/useIsTruncated.ts +0 -28
- package/src/RedactoPrivacyCenter/components/AppShell/hooks/useKeyboardShortcut.ts +0 -40
- package/src/RedactoPrivacyCenter/components/AppShell/hooks/useSidebarState.ts +0 -62
- package/src/RedactoPrivacyCenter/components/AppShell/usePrivacyCenterExitAction.ts +0 -36
- package/src/RedactoPrivacyCenter/components/CaseDetails/AttachmentCard.tsx +0 -38
- package/src/RedactoPrivacyCenter/components/CaseDetails/ChatBubble.tsx +0 -31
- package/src/RedactoPrivacyCenter/components/CaseDetails/DocumentRequestCard.tsx +0 -79
- package/src/RedactoPrivacyCenter/components/CaseDetails/FinalizedTooltipWrapper.tsx +0 -25
- package/src/RedactoPrivacyCenter/components/CaseDetails/MessageComposer.tsx +0 -96
- package/src/RedactoPrivacyCenter/components/CaseDetails/MessageItem.tsx +0 -97
- package/src/RedactoPrivacyCenter/components/CaseDetails/MessagesTab.tsx +0 -156
- package/src/RedactoPrivacyCenter/components/CaseDetails/RequestDetailsTab.tsx +0 -171
- package/src/RedactoPrivacyCenter/components/CaseDetails/StatusEvent.tsx +0 -23
- package/src/RedactoPrivacyCenter/components/CaseDetails/useFileUpload.ts +0 -116
- package/src/RedactoPrivacyCenter/components/CaseDetails/useMessagePolling.ts +0 -43
- package/src/RedactoPrivacyCenter/components/CaseDetails/utils.ts +0 -71
- package/src/RedactoPrivacyCenter/components/CaseDetailsModal.tsx +0 -469
- package/src/RedactoPrivacyCenter/components/CaseHistory.tsx +0 -426
- package/src/RedactoPrivacyCenter/components/ConsentManager.tsx +0 -1206
- package/src/RedactoPrivacyCenter/components/ConsentManagerCells.tsx +0 -218
- package/src/RedactoPrivacyCenter/components/ConsentManagerColumns.tsx +0 -138
- package/src/RedactoPrivacyCenter/components/ConsentManagerConstants.ts +0 -7
- package/src/RedactoPrivacyCenter/components/ConsentManagerExpandedRow.tsx +0 -179
- package/src/RedactoPrivacyCenter/components/ConsentManagerGroupedColumns.tsx +0 -318
- package/src/RedactoPrivacyCenter/components/ConsentManagerProductCards.tsx +0 -333
- package/src/RedactoPrivacyCenter/components/ConsentManagerPurposeCards.tsx +0 -102
- package/src/RedactoPrivacyCenter/components/ConsentManagerTableSkeleton.tsx +0 -159
- package/src/RedactoPrivacyCenter/components/DataRequest/CorrectionDataSection.tsx +0 -189
- package/src/RedactoPrivacyCenter/components/DataRequest/GrievanceDataSection.tsx +0 -118
- package/src/RedactoPrivacyCenter/components/DataRequest/NominationDataSection.tsx +0 -66
- package/src/RedactoPrivacyCenter/components/DataRequest/ProductSelectionSection.tsx +0 -222
- package/src/RedactoPrivacyCenter/components/DataRequest/PurposeSelectionSection.tsx +0 -331
- package/src/RedactoPrivacyCenter/components/Form.tsx +0 -1821
- package/src/RedactoPrivacyCenter/components/GrievanceTable.tsx +0 -174
- package/src/RedactoPrivacyCenter/components/GrievanceTablePagination.tsx +0 -337
- package/src/RedactoPrivacyCenter/components/ModifyConsentModal.tsx +0 -334
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationBell.tsx +0 -173
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationCTAButton.tsx +0 -18
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationDropdown.tsx +0 -54
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationDropdownItem.tsx +0 -57
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationIcon.tsx +0 -19
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationListPanel.tsx +0 -92
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationRefreshButton.tsx +0 -20
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationRow.tsx +0 -58
- package/src/RedactoPrivacyCenter/components/NotificationHub/StatCard.tsx +0 -10
- package/src/RedactoPrivacyCenter/components/NotificationHub/useNotificationActions.ts +0 -112
- package/src/RedactoPrivacyCenter/components/NotificationHub/utils.ts +0 -27
- package/src/RedactoPrivacyCenter/components/Pagination.tsx +0 -140
- package/src/RedactoPrivacyCenter/components/PrivacyCenterEmptyState.tsx +0 -76
- package/src/RedactoPrivacyCenter/components/PrivacyCenterSessionExpired.tsx +0 -97
- package/src/RedactoPrivacyCenter/components/ReceiptsList.tsx +0 -454
- package/src/RedactoPrivacyCenter/components/RequestSubmit.tsx +0 -270
- package/src/RedactoPrivacyCenter/components/SelectUser.tsx +0 -95
- package/src/RedactoPrivacyCenter/components/SelectUserGate.tsx +0 -195
- package/src/RedactoPrivacyCenter/components/SideMenuBarPC/constants.tsx +0 -25
- package/src/RedactoPrivacyCenter/components/SideMenuBarPC/types.ts +0 -21
- package/src/RedactoPrivacyCenter/components/caseHistoryColumns.tsx +0 -159
- package/src/RedactoPrivacyCenter/components/constant.ts +0 -52
- package/src/RedactoPrivacyCenter/components/groupHelpers.ts +0 -155
- package/src/RedactoPrivacyCenter/components/receiptColumns.tsx +0 -203
- package/src/RedactoPrivacyCenter/components/types.ts +0 -123
- package/src/RedactoPrivacyCenter/components/utils.tsx +0 -10
- package/src/RedactoPrivacyCenter/config/routes.ts +0 -9
- package/src/RedactoPrivacyCenter/config/table.ts +0 -25
- package/src/RedactoPrivacyCenter/context/AuthContext.tsx +0 -252
- package/src/RedactoPrivacyCenter/context/BaseUrlContext.tsx +0 -47
- package/src/RedactoPrivacyCenter/context/BrandingContext.tsx +0 -52
- package/src/RedactoPrivacyCenter/context/DataAvailabilityContext.session-expired.test.tsx +0 -92
- package/src/RedactoPrivacyCenter/context/DataAvailabilityContext.tsx +0 -181
- package/src/RedactoPrivacyCenter/context/LocaleContext.tsx +0 -11
- package/src/RedactoPrivacyCenter/context/NavigationContext.tsx +0 -96
- package/src/RedactoPrivacyCenter/context/OrganizationContext.tsx +0 -30
- package/src/RedactoPrivacyCenter/context/PageChromeContext.tsx +0 -80
- package/src/RedactoPrivacyCenter/context/ProfileSwitchContext.tsx +0 -15
- package/src/RedactoPrivacyCenter/context/types.ts +0 -57
- package/src/RedactoPrivacyCenter/lib/api.ts +0 -759
- package/src/RedactoPrivacyCenter/lib/consent-manager/utils.tsx +0 -67
- package/src/RedactoPrivacyCenter/lib/constants.ts +0 -283
- package/src/RedactoPrivacyCenter/lib/i18n.ts +0 -81
- package/src/RedactoPrivacyCenter/lib/locales.ts +0 -102
- package/src/RedactoPrivacyCenter/lib/queries.ts +0 -141
- package/src/RedactoPrivacyCenter/lib/sandbox.ts +0 -104
- package/src/RedactoPrivacyCenter/lib/types.ts +0 -896
- package/src/RedactoPrivacyCenter/lib/useCurrentLanguage.ts +0 -37
- package/src/RedactoPrivacyCenter/lib/utils.refresh-circuit.test.ts +0 -127
- package/src/RedactoPrivacyCenter/lib/utils.refresh-storage.test.ts +0 -85
- package/src/RedactoPrivacyCenter/lib/utils.session-expired.test.ts +0 -109
- package/src/RedactoPrivacyCenter/lib/utils.ts +0 -798
- package/src/RedactoPrivacyCenter/locales/as/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/bn/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/brx/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/doi/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/en/translation.json +0 -357
- package/src/RedactoPrivacyCenter/locales/gom/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/gu/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/hi/translation.json +0 -345
- package/src/RedactoPrivacyCenter/locales/kn/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/ks/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/mai/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/ml/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/mni-Mtei/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/mr/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/ne/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/or/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/pa/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/sa/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/sat/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/sd/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/ta/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/te/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/ur/translation.json +0 -342
- package/src/RedactoPrivacyCenter/styles/applyBrandingTheme.ts +0 -66
- package/src/RedactoPrivacyCenter/styles/base.css +0 -117
- package/src/RedactoPrivacyCenter/styles/injectStyles.ts +0 -3108
- package/src/RedactoPrivacyCenter/styles/pcStyles.ts +0 -831
- package/src/RedactoPrivacyCenter/styles/responsive.ts +0 -138
- package/src/RedactoPrivacyCenter/styles/variables.css +0 -96
- package/src/RedactoPrivacyCenter/table/AdvancedTable.tsx +0 -387
- package/src/RedactoPrivacyCenter/table/AdvancedTablePagination.tsx +0 -468
- package/src/RedactoPrivacyCenter/table/index.ts +0 -2
- package/src/RedactoPrivacyCenter/types/images.d.ts +0 -29
- package/src/RedactoPrivacyCenter/ui/Footer.tsx +0 -69
- package/src/RedactoPrivacyCenter/ui/FormBlockWrapper.tsx +0 -54
- package/src/RedactoPrivacyCenter/ui/PCAccordion.tsx +0 -93
- package/src/RedactoPrivacyCenter/ui/PCActionIcon.tsx +0 -47
- package/src/RedactoPrivacyCenter/ui/PCAvatar.test.tsx +0 -83
- package/src/RedactoPrivacyCenter/ui/PCAvatar.tsx +0 -93
- package/src/RedactoPrivacyCenter/ui/PCBadge.tsx +0 -48
- package/src/RedactoPrivacyCenter/ui/PCButton.tsx +0 -77
- package/src/RedactoPrivacyCenter/ui/PCCheckbox.tsx +0 -55
- package/src/RedactoPrivacyCenter/ui/PCCollapse.tsx +0 -107
- package/src/RedactoPrivacyCenter/ui/PCEmpty.tsx +0 -35
- package/src/RedactoPrivacyCenter/ui/PCInput.tsx +0 -132
- package/src/RedactoPrivacyCenter/ui/PCLoader.tsx +0 -31
- package/src/RedactoPrivacyCenter/ui/PCModal.tsx +0 -106
- package/src/RedactoPrivacyCenter/ui/PCPopover.tsx +0 -206
- package/src/RedactoPrivacyCenter/ui/PCSelect.tsx +0 -433
- package/src/RedactoPrivacyCenter/ui/PCTable.tsx +0 -149
- package/src/RedactoPrivacyCenter/ui/PCText.tsx +0 -41
- package/src/RedactoPrivacyCenter/ui/PCTextarea.tsx +0 -43
- package/src/RedactoPrivacyCenter/ui/PCTitle.tsx +0 -37
- package/src/RedactoPrivacyCenter/ui/PCTooltip.tsx +0 -121
- package/src/RedactoPrivacyCenter/ui/SimpleBar.tsx +0 -25
- package/src/RedactoPrivacyCenter/ui/StatusBadge.tsx +0 -53
- package/src/RedactoPrivacyCenter/ui/index.ts +0 -18
- package/src/RedactoPrivacyCenter/utils/cn.ts +0 -28
- package/src/RedactoPrivacyCenter/utils/date.ts +0 -48
- package/src/RedactoPrivacyCenter/utils/status.ts +0 -111
- package/src/RedactoPrivacyCenter/utils/toast.ts +0 -130
- package/src/index.ts +0 -19
- package/src/privacy-center.ts +0 -113
- package/src/shared/api-errors.ts +0 -180
- package/src/shared/notice-consent-status.ts +0 -190
- package/src/shared/sandbox.ts +0 -6
- package/src/types/css.d.ts +0 -4
- package/src/types/images.d.ts +0 -19
- package/src/types/react-jsx.d.ts +0 -26
- package/tests/DataAvailabilityContext.test.tsx +0 -123
- package/tests/Form.test.tsx +0 -1424
- package/tests/ManageConsentErrorMapping.test.tsx +0 -85
- package/tests/ProductSelectionSection.test.tsx +0 -328
- package/tests/RequestSubmit.test.tsx +0 -135
- package/tests/RevocablePurpose.test.tsx +0 -146
- package/tests/RevokeWarningMessage.test.tsx +0 -151
- package/tests/consentClient.test.ts +0 -217
- package/tests/manageConsentServer.test.ts +0 -38
- package/tests/mocks.ts +0 -257
- package/tests/resolveContactFromJwt.test.ts +0 -44
- package/tests/setup.ts +0 -16
- package/tsconfig.json +0 -16
- package/tsup.config.ts +0 -31
- package/vitest.config.ts +0 -16
|
@@ -1,1003 +0,0 @@
|
|
|
1
|
-
import { apiFetch, ApiError } from "./fetcher";
|
|
2
|
-
import type { ApiFetchOptions, ApiResponse } from "./fetcher";
|
|
3
|
-
import {
|
|
4
|
-
isSandboxMode,
|
|
5
|
-
sandboxAuthHeaders,
|
|
6
|
-
sandboxContact,
|
|
7
|
-
sandboxQueryIdentity,
|
|
8
|
-
} from "../lib/sandbox";
|
|
9
|
-
import type {
|
|
10
|
-
CaseMessage,
|
|
11
|
-
IdentityListResponse,
|
|
12
|
-
MessageDocument,
|
|
13
|
-
NotificationActionResponse,
|
|
14
|
-
NotificationListResponse,
|
|
15
|
-
NotificationQueryParams,
|
|
16
|
-
NotificationSummary,
|
|
17
|
-
SelectPrincipalResponse,
|
|
18
|
-
UnreadCountResponse,
|
|
19
|
-
UploadDocumentResponse,
|
|
20
|
-
} from "../lib/types";
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Base request parameters for consent service calls
|
|
24
|
-
*/
|
|
25
|
-
export type BaseRequest = {
|
|
26
|
-
organisationUuid: string;
|
|
27
|
-
workspaceUuid: string;
|
|
28
|
-
authToken: string;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Consent service client factory.
|
|
33
|
-
* Creates a client instance with a specific base URL.
|
|
34
|
-
* @param baseUrl - Consent server base URL (Python service, e.g. http://host/consent)
|
|
35
|
-
* @param ledgerBaseUrl - Go ledger base URL (e.g. http://host:8090/consent-ledger).
|
|
36
|
-
* Used for user-consents reads/writes served from the ledger's `/public/...` paths.
|
|
37
|
-
* When omitted, those calls fall back to the legacy Python
|
|
38
|
-
* `/dsar/privacy-center` endpoints and payloads (pre-ledger behavior), so
|
|
39
|
-
* integrations without a deployed ledger keep working.
|
|
40
|
-
*/
|
|
41
|
-
export function createConsentClient(baseUrl: string, ledgerBaseUrl?: string) {
|
|
42
|
-
const ledgerConfigured = Boolean(ledgerBaseUrl);
|
|
43
|
-
// Sandbox mode never routes to the Go ledger (it has no sandbox / test::
|
|
44
|
-
// support). A sandbox token forces the legacy consent-server path regardless
|
|
45
|
-
// of ledgerBaseUrl, so isolation can't be bypassed by also configuring a ledger.
|
|
46
|
-
const useLedger = () => ledgerConfigured && !isSandboxMode();
|
|
47
|
-
const ledgerBase = (ledgerBaseUrl ?? "").replace(/\/$/, "");
|
|
48
|
-
/**
|
|
49
|
-
* Privacy Center API fetch wrapper that uses Authorization: Bearer header.
|
|
50
|
-
* Privacy center endpoints require JWT tokens in Authorization header, not X-Auth-Token.
|
|
51
|
-
*/
|
|
52
|
-
async function privacyCenterApiFetch<T>(
|
|
53
|
-
url: string,
|
|
54
|
-
options: ApiFetchOptions & { authToken?: string }
|
|
55
|
-
): Promise<T> {
|
|
56
|
-
const { authToken, getAuthToken, headers = {}, ...fetchOptions } = options;
|
|
57
|
-
|
|
58
|
-
// Build headers using Headers object
|
|
59
|
-
const requestHeaders = new Headers();
|
|
60
|
-
|
|
61
|
-
// Set default headers (skip Content-Type for FormData)
|
|
62
|
-
const isFormData = fetchOptions.body instanceof FormData;
|
|
63
|
-
if (!isFormData) {
|
|
64
|
-
requestHeaders.set("Content-Type", "application/json");
|
|
65
|
-
}
|
|
66
|
-
requestHeaders.set("Accept", "application/json");
|
|
67
|
-
|
|
68
|
-
// Add custom headers from options
|
|
69
|
-
if (headers && typeof headers === "object") {
|
|
70
|
-
if (headers instanceof Headers) {
|
|
71
|
-
headers.forEach((value, key) => {
|
|
72
|
-
requestHeaders.set(key, value);
|
|
73
|
-
});
|
|
74
|
-
} else {
|
|
75
|
-
Object.entries(headers as Record<string, string>).forEach(
|
|
76
|
-
([key, value]) => {
|
|
77
|
-
if (value) {
|
|
78
|
-
requestHeaders.set(key, value);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Sandbox PoC: send only the X-Consent-Token credential (no JWT bearer). Set
|
|
86
|
-
// last so it wins over any caller-supplied Authorization header. The acting
|
|
87
|
-
// identity travels in the request payload -- query params on reads, the body
|
|
88
|
-
// on writes -- never a header.
|
|
89
|
-
const sandboxHeaders = sandboxAuthHeaders();
|
|
90
|
-
if (sandboxHeaders) {
|
|
91
|
-
Object.entries(sandboxHeaders).forEach(([key, value]) => {
|
|
92
|
-
requestHeaders.set(key, value);
|
|
93
|
-
});
|
|
94
|
-
} else {
|
|
95
|
-
// Add Authorization Bearer token for privacy center APIs
|
|
96
|
-
const token = authToken || (getAuthToken ? await getAuthToken() : null);
|
|
97
|
-
if (token) {
|
|
98
|
-
const trimmedToken = token.trim();
|
|
99
|
-
// Format token with Bearer prefix if not already present
|
|
100
|
-
const bearerToken = trimmedToken.startsWith('Bearer ')
|
|
101
|
-
? trimmedToken
|
|
102
|
-
: `Bearer ${trimmedToken}`;
|
|
103
|
-
requestHeaders.set("Authorization", bearerToken);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Build fetch options
|
|
108
|
-
const fetchOptionsFinal: RequestInit = {
|
|
109
|
-
...fetchOptions,
|
|
110
|
-
headers: requestHeaders,
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
try {
|
|
114
|
-
const response = await fetch(url, fetchOptionsFinal);
|
|
115
|
-
|
|
116
|
-
// Handle non-OK responses
|
|
117
|
-
if (!response.ok) {
|
|
118
|
-
let errorMessage = `Request failed with status ${response.status}`;
|
|
119
|
-
let errorCode: string | undefined;
|
|
120
|
-
let errorDetail: unknown;
|
|
121
|
-
|
|
122
|
-
try {
|
|
123
|
-
const errorData = (await response.json()) as {
|
|
124
|
-
detail?: unknown;
|
|
125
|
-
message?: string;
|
|
126
|
-
code?: string;
|
|
127
|
-
} | null;
|
|
128
|
-
if (errorData) {
|
|
129
|
-
errorDetail = errorData.detail;
|
|
130
|
-
if (typeof errorData.code === "string") {
|
|
131
|
-
errorCode = errorData.code;
|
|
132
|
-
}
|
|
133
|
-
if ("detail" in errorData && errorData.detail) {
|
|
134
|
-
errorMessage =
|
|
135
|
-
typeof errorData.detail === "string"
|
|
136
|
-
? errorData.detail
|
|
137
|
-
: JSON.stringify(errorData.detail, null, 2);
|
|
138
|
-
} else if ("message" in errorData && errorData.message) {
|
|
139
|
-
errorMessage = errorData.message;
|
|
140
|
-
} else if ("code" in errorData && errorData.code) {
|
|
141
|
-
// e.g. { code: "empty_file" } or { code: "document_already_exists" }
|
|
142
|
-
errorMessage = errorData.code;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
} catch {
|
|
146
|
-
// If response is not JSON, try to get text
|
|
147
|
-
try {
|
|
148
|
-
const errorText = await response.text();
|
|
149
|
-
if (errorText) {
|
|
150
|
-
errorMessage = errorText;
|
|
151
|
-
}
|
|
152
|
-
} catch {
|
|
153
|
-
// Ignore parsing errors
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// Throw a typed error carrying the status/code. The `[status]` prefix is
|
|
158
|
-
// kept in the message for back-compat with callers that branch on it
|
|
159
|
-
// (e.g. getFormData checks for "404").
|
|
160
|
-
throw new ApiError(`[${response.status}] ${errorMessage}`, {
|
|
161
|
-
status: response.status,
|
|
162
|
-
code: errorCode,
|
|
163
|
-
detail: errorDetail,
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Parse JSON response
|
|
168
|
-
const contentType = response.headers.get("Content-Type") || "";
|
|
169
|
-
if (!contentType.includes("application/json")) {
|
|
170
|
-
const textResponse = await response.text();
|
|
171
|
-
throw new Error(
|
|
172
|
-
`Expected JSON response, got ${contentType}: ${textResponse}`
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const data = (await response.json()) as ApiResponse<T> | T;
|
|
177
|
-
|
|
178
|
-
// Handle wrapped API responses (code, status, detail format)
|
|
179
|
-
if (
|
|
180
|
-
typeof data === "object" &&
|
|
181
|
-
data !== null &&
|
|
182
|
-
"code" in data &&
|
|
183
|
-
"status" in data &&
|
|
184
|
-
"detail" in data
|
|
185
|
-
) {
|
|
186
|
-
const apiResponse = data as ApiResponse<T>;
|
|
187
|
-
return apiResponse.detail as T;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return data as T;
|
|
191
|
-
} catch (error) {
|
|
192
|
-
if (error instanceof Error) {
|
|
193
|
-
throw error;
|
|
194
|
-
}
|
|
195
|
-
throw new Error(`Unknown error occurred: ${String(error)}`);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function privacyCenterUrl(baseRequest: BaseRequest, path: string): string {
|
|
200
|
-
return `${baseUrl}/organisations/${baseRequest.organisationUuid}/workspaces/${baseRequest.workspaceUuid}/dsar/privacy-center${path}`;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
function ledgerUrl(baseRequest: BaseRequest, path: string): string {
|
|
204
|
-
if (!useLedger()) {
|
|
205
|
-
throw new Error("ledgerUrl called without a configured ledgerBaseUrl");
|
|
206
|
-
}
|
|
207
|
-
return `${ledgerBase}/public/organisations/${baseRequest.organisationUuid}/workspaces/${baseRequest.workspaceUuid}${path}`;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function caseUrl(baseRequest: BaseRequest, caseUuid: string, path = ''): string {
|
|
211
|
-
return privacyCenterUrl(baseRequest, `/cases/${caseUuid}${path}`);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
function notificationUrl(baseRequest: BaseRequest, path = ''): string {
|
|
215
|
-
const identitySuffix = sandboxIdentitySuffix();
|
|
216
|
-
if (!identitySuffix) {
|
|
217
|
-
return privacyCenterUrl(baseRequest, `/notifications${path}`);
|
|
218
|
-
}
|
|
219
|
-
const separator = path.includes('?') ? `&${identitySuffix.slice(1)}` : identitySuffix;
|
|
220
|
-
return privacyCenterUrl(baseRequest, `/notifications${path}${separator}`);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
function resolveAuthToken(authToken: string | undefined, baseRequest: BaseRequest): string {
|
|
224
|
-
return authToken || baseRequest.authToken;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Append the sandbox acting identity (`primary_email` / `primary_mobile`) to a
|
|
229
|
-
* query-param bag when sandbox mode is active; a no-op otherwise. The server
|
|
230
|
-
* resolves the acting test identity from these query params on reads (there is
|
|
231
|
-
* no subject header). The credential is the X-Consent-Token header set in
|
|
232
|
-
* privacyCenterApiFetch.
|
|
233
|
-
*/
|
|
234
|
-
function appendSandboxIdentity(queryParams: URLSearchParams): void {
|
|
235
|
-
const identity = sandboxQueryIdentity();
|
|
236
|
-
if (identity) {
|
|
237
|
-
Object.entries(identity).forEach(([key, value]) => {
|
|
238
|
-
queryParams.append(key, value);
|
|
239
|
-
});
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* The sandbox acting-identity query suffix (`?primary_email=...` /
|
|
245
|
-
* `?primary_mobile=...`) for endpoints that build a bare URL with no other
|
|
246
|
-
* query params (the case-communication reads/POSTs). Empty string outside
|
|
247
|
-
* sandbox mode, so the JWT path is unchanged.
|
|
248
|
-
*/
|
|
249
|
-
function sandboxIdentitySuffix(): string {
|
|
250
|
-
const queryParams = new URLSearchParams();
|
|
251
|
-
appendSandboxIdentity(queryParams);
|
|
252
|
-
const queryString = queryParams.toString();
|
|
253
|
-
return queryString ? `?${queryString}` : "";
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
return {
|
|
257
|
-
/**
|
|
258
|
-
* Get form data (privacy center)
|
|
259
|
-
*/
|
|
260
|
-
async getFormData(
|
|
261
|
-
baseRequest: BaseRequest,
|
|
262
|
-
contact: string,
|
|
263
|
-
authToken?: string,
|
|
264
|
-
options?: ApiFetchOptions & { useSessionAuth?: boolean },
|
|
265
|
-
language?: string
|
|
266
|
-
): Promise<unknown> {
|
|
267
|
-
const queryParams = new URLSearchParams();
|
|
268
|
-
if (language) queryParams.append("language", language);
|
|
269
|
-
const queryString = queryParams.toString();
|
|
270
|
-
const url = privacyCenterUrl(baseRequest, `/form/data${queryString ? `?${queryString}` : ""}`);
|
|
271
|
-
const { useSessionAuth = false, getAuthToken, ...fetchOptions } = options || {};
|
|
272
|
-
|
|
273
|
-
// Case management uses session-based auth (X-Auth-Token)
|
|
274
|
-
// Privacy center uses JWT Bearer tokens (Authorization: Bearer)
|
|
275
|
-
if (useSessionAuth) {
|
|
276
|
-
return apiFetch(url, {
|
|
277
|
-
...fetchOptions,
|
|
278
|
-
method: "POST",
|
|
279
|
-
body: JSON.stringify({ contact }),
|
|
280
|
-
getAuthToken,
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Privacy center: use JWT Bearer token
|
|
285
|
-
return privacyCenterApiFetch(url, {
|
|
286
|
-
...fetchOptions,
|
|
287
|
-
method: "POST",
|
|
288
|
-
body: JSON.stringify({ contact }),
|
|
289
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
290
|
-
});
|
|
291
|
-
},
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* Create case request (privacy center or case management)
|
|
295
|
-
*/
|
|
296
|
-
async createCaseRequest(
|
|
297
|
-
baseRequest: BaseRequest,
|
|
298
|
-
payload: unknown,
|
|
299
|
-
authToken?: string,
|
|
300
|
-
options?: ApiFetchOptions & { useSessionAuth?: boolean }
|
|
301
|
-
): Promise<unknown> {
|
|
302
|
-
const url = privacyCenterUrl(baseRequest, '/case');
|
|
303
|
-
const { useSessionAuth = false, getAuthToken, ...fetchOptions } = options || {};
|
|
304
|
-
|
|
305
|
-
// Sandbox mode: the acting test identity is the single `contact` field
|
|
306
|
-
// (the server has no subject header; it namespaces this identity `test::`).
|
|
307
|
-
// Merge it into the body only when sandbox mode is active and the payload
|
|
308
|
-
// is a plain object; the JWT path is left byte-for-byte unchanged.
|
|
309
|
-
const contact = sandboxContact();
|
|
310
|
-
const requestPayload =
|
|
311
|
-
contact && payload && typeof payload === "object"
|
|
312
|
-
? { ...(payload as Record<string, unknown>), contact }
|
|
313
|
-
: payload;
|
|
314
|
-
|
|
315
|
-
// Case management uses session-based auth (X-Auth-Token)
|
|
316
|
-
// Privacy center uses JWT Bearer tokens (Authorization: Bearer)
|
|
317
|
-
if (useSessionAuth) {
|
|
318
|
-
return apiFetch(url, {
|
|
319
|
-
...fetchOptions,
|
|
320
|
-
method: "POST",
|
|
321
|
-
body: JSON.stringify(requestPayload),
|
|
322
|
-
getAuthToken,
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// Privacy center: use JWT Bearer token
|
|
327
|
-
return privacyCenterApiFetch(url, {
|
|
328
|
-
...fetchOptions,
|
|
329
|
-
method: "POST",
|
|
330
|
-
body: JSON.stringify(requestPayload),
|
|
331
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
332
|
-
});
|
|
333
|
-
},
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* Create OTP (public)
|
|
337
|
-
*/
|
|
338
|
-
async createOtp(
|
|
339
|
-
organisationId: string,
|
|
340
|
-
workspaceId: string,
|
|
341
|
-
email: string,
|
|
342
|
-
options?: Omit<ApiFetchOptions, "getAuthToken">
|
|
343
|
-
): Promise<unknown> {
|
|
344
|
-
const url = `${baseUrl}/public/organisations/${organisationId}/workspaces/${workspaceId}/otp/create`;
|
|
345
|
-
return apiFetch(url, {
|
|
346
|
-
...options,
|
|
347
|
-
method: "POST",
|
|
348
|
-
body: JSON.stringify({ to: email, channel: "email" }),
|
|
349
|
-
});
|
|
350
|
-
},
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* Verify OTP (public)
|
|
354
|
-
*/
|
|
355
|
-
async verifyOtp(
|
|
356
|
-
organisationId: string,
|
|
357
|
-
workspaceId: string,
|
|
358
|
-
otpId: string,
|
|
359
|
-
otp: string,
|
|
360
|
-
options?: Omit<ApiFetchOptions, "getAuthToken">
|
|
361
|
-
): Promise<unknown> {
|
|
362
|
-
const url = `${baseUrl}/public/organisations/${organisationId}/workspaces/${workspaceId}/otp/verify`;
|
|
363
|
-
return apiFetch(url, {
|
|
364
|
-
...options,
|
|
365
|
-
method: "POST",
|
|
366
|
-
body: JSON.stringify({ uuid: otpId, otp }),
|
|
367
|
-
});
|
|
368
|
-
},
|
|
369
|
-
|
|
370
|
-
/**
|
|
371
|
-
* Exchange one-time token for JWT tokens (public)
|
|
372
|
-
*/
|
|
373
|
-
async exchangeToken(
|
|
374
|
-
token: string,
|
|
375
|
-
): Promise<unknown> {
|
|
376
|
-
const url = `${baseUrl}/public/tokens/token-exchange?token=${encodeURIComponent(token)}`;
|
|
377
|
-
const response = await fetch(url, {
|
|
378
|
-
method: "GET",
|
|
379
|
-
headers: { "Accept": "application/json" },
|
|
380
|
-
});
|
|
381
|
-
|
|
382
|
-
if (!response.ok) {
|
|
383
|
-
const errorData = await response.json().catch(() => null) as { detail?: string; message?: string } | null;
|
|
384
|
-
throw new Error(
|
|
385
|
-
errorData?.detail || errorData?.message || `Token exchange failed with status ${response.status}`
|
|
386
|
-
);
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
const data = await response.json() as { code?: number; status?: string; detail?: unknown };
|
|
390
|
-
if (data && typeof data === "object" && "code" in data && "status" in data && "detail" in data) {
|
|
391
|
-
return data.detail;
|
|
392
|
-
}
|
|
393
|
-
return data;
|
|
394
|
-
},
|
|
395
|
-
|
|
396
|
-
/**
|
|
397
|
-
* Refresh OTP token (public)
|
|
398
|
-
*/
|
|
399
|
-
async refreshOtpToken(
|
|
400
|
-
organisationId: string,
|
|
401
|
-
workspaceId: string,
|
|
402
|
-
refreshToken: string,
|
|
403
|
-
options?: Omit<ApiFetchOptions, "getAuthToken">
|
|
404
|
-
): Promise<unknown> {
|
|
405
|
-
const url = `${baseUrl}/public/organisations/${organisationId}/workspaces/${workspaceId}/otp/refresh`;
|
|
406
|
-
return apiFetch(url, {
|
|
407
|
-
...options,
|
|
408
|
-
method: "POST",
|
|
409
|
-
body: JSON.stringify({ refresh_token: refreshToken }),
|
|
410
|
-
});
|
|
411
|
-
},
|
|
412
|
-
|
|
413
|
-
/**
|
|
414
|
-
* Get products
|
|
415
|
-
*/
|
|
416
|
-
async getProducts(
|
|
417
|
-
baseRequest: BaseRequest,
|
|
418
|
-
skip: number = 0,
|
|
419
|
-
limit: number = 10,
|
|
420
|
-
options?: Omit<ApiFetchOptions, "getAuthToken">
|
|
421
|
-
): Promise<unknown> {
|
|
422
|
-
const url = `${baseUrl}/organisations/${baseRequest.organisationUuid}/workspaces/${baseRequest.workspaceUuid}/notice-management/products/?skip=${skip}&limit=${limit}`;
|
|
423
|
-
return apiFetch<unknown>(url, {
|
|
424
|
-
...options,
|
|
425
|
-
getAuthToken: async () => baseRequest.authToken,
|
|
426
|
-
});
|
|
427
|
-
},
|
|
428
|
-
|
|
429
|
-
/**
|
|
430
|
-
* Get user consents (privacy center)
|
|
431
|
-
*/
|
|
432
|
-
async getUserConsents(
|
|
433
|
-
baseRequest: BaseRequest,
|
|
434
|
-
params: {
|
|
435
|
-
offset?: number;
|
|
436
|
-
limit?: number;
|
|
437
|
-
nominated_offset?: number;
|
|
438
|
-
nominated_limit?: number;
|
|
439
|
-
status?: string;
|
|
440
|
-
product_uuid?: string;
|
|
441
|
-
search?: string;
|
|
442
|
-
language?: string;
|
|
443
|
-
},
|
|
444
|
-
authToken?: string,
|
|
445
|
-
options?: Omit<ApiFetchOptions, "getAuthToken">
|
|
446
|
-
): Promise<unknown> {
|
|
447
|
-
const queryParams = new URLSearchParams();
|
|
448
|
-
if (params.offset !== undefined) queryParams.append("offset", params.offset.toString());
|
|
449
|
-
if (params.limit !== undefined) queryParams.append("limit", params.limit.toString());
|
|
450
|
-
if (params.nominated_offset !== undefined) queryParams.append("nominated_offset", params.nominated_offset.toString());
|
|
451
|
-
if (params.nominated_limit !== undefined) queryParams.append("nominated_limit", params.nominated_limit.toString());
|
|
452
|
-
if (params.search) queryParams.append("search", params.search);
|
|
453
|
-
if (params.status) queryParams.append("status", params.status);
|
|
454
|
-
if (params.product_uuid) queryParams.append("product_uuid", params.product_uuid);
|
|
455
|
-
if (params.language) queryParams.append("language", params.language);
|
|
456
|
-
// Sandbox mode: the acting identity travels as query params
|
|
457
|
-
// (primary_email / primary_mobile); the credential is the X-Consent-Token header.
|
|
458
|
-
appendSandboxIdentity(queryParams);
|
|
459
|
-
const queryString = queryParams.toString();
|
|
460
|
-
const suffix = `/user-consents${queryString ? `?${queryString}` : ""}`;
|
|
461
|
-
const url = useLedger()
|
|
462
|
-
? ledgerUrl(baseRequest, suffix)
|
|
463
|
-
: privacyCenterUrl(baseRequest, suffix);
|
|
464
|
-
return privacyCenterApiFetch(url, {
|
|
465
|
-
...options,
|
|
466
|
-
method: "GET",
|
|
467
|
-
cache: "no-store",
|
|
468
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
469
|
-
});
|
|
470
|
-
},
|
|
471
|
-
|
|
472
|
-
/**
|
|
473
|
-
* Get purposes for a single product card (privacy center) — sister endpoint
|
|
474
|
-
* for lazy-loading purposes when a card returns has_more_purposes: true.
|
|
475
|
-
*/
|
|
476
|
-
async getGroupPurposes(
|
|
477
|
-
baseRequest: BaseRequest,
|
|
478
|
-
productUuid: string,
|
|
479
|
-
params: {
|
|
480
|
-
offset?: number;
|
|
481
|
-
limit?: number;
|
|
482
|
-
status?: string;
|
|
483
|
-
search?: string;
|
|
484
|
-
language?: string;
|
|
485
|
-
nominator_uuid?: string;
|
|
486
|
-
},
|
|
487
|
-
authToken?: string,
|
|
488
|
-
options?: Omit<ApiFetchOptions, "getAuthToken">
|
|
489
|
-
): Promise<unknown> {
|
|
490
|
-
const queryParams = new URLSearchParams();
|
|
491
|
-
if (params.offset !== undefined) queryParams.append("offset", params.offset.toString());
|
|
492
|
-
if (params.limit !== undefined) queryParams.append("limit", params.limit.toString());
|
|
493
|
-
if (params.status) queryParams.append("status", params.status);
|
|
494
|
-
if (params.search) queryParams.append("search", params.search);
|
|
495
|
-
if (params.language) queryParams.append("language", params.language);
|
|
496
|
-
if (params.nominator_uuid) queryParams.append("nominator_uuid", params.nominator_uuid);
|
|
497
|
-
// Sandbox mode: the acting identity travels as query params
|
|
498
|
-
// (primary_email / primary_mobile); the credential is the X-Consent-Token header.
|
|
499
|
-
appendSandboxIdentity(queryParams);
|
|
500
|
-
const queryString = queryParams.toString();
|
|
501
|
-
const suffix = `/user-consents/${productUuid}/purposes${queryString ? `?${queryString}` : ""}`;
|
|
502
|
-
const url = useLedger()
|
|
503
|
-
? ledgerUrl(baseRequest, suffix)
|
|
504
|
-
: privacyCenterUrl(baseRequest, suffix);
|
|
505
|
-
return privacyCenterApiFetch(url, {
|
|
506
|
-
...options,
|
|
507
|
-
method: "GET",
|
|
508
|
-
cache: "no-store",
|
|
509
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
510
|
-
});
|
|
511
|
-
},
|
|
512
|
-
|
|
513
|
-
/**
|
|
514
|
-
* Manage consent (privacy center) - revoke, regrant, or renew.
|
|
515
|
-
*
|
|
516
|
-
* The Go ledger has no manage-consent route, so with a ledger configured
|
|
517
|
-
* this is expressed as a `partial` submit-consent on the ledger — mirroring
|
|
518
|
-
* the Python dual-write relay (`build_consent_management_payload`): the
|
|
519
|
-
* affected purpose is re-submitted with `selected: false` to revoke or
|
|
520
|
-
* `selected: true` to regrant/renew, and `partial: true` so the rest of the
|
|
521
|
-
* notice's purposes are left untouched. The principal is resolved from the
|
|
522
|
-
* JWT, so no `contact`/identifiers are sent in the body, and
|
|
523
|
-
* `consent_event_uuid` is omitted so the ledger mints a fresh event.
|
|
524
|
-
*
|
|
525
|
-
* Without a ledger, the legacy Python `/manage-consent?status=` endpoint is
|
|
526
|
-
* used with its `{ purpose_uuid, contact, ... }` payload.
|
|
527
|
-
*/
|
|
528
|
-
async manageConsent(
|
|
529
|
-
baseRequest: BaseRequest,
|
|
530
|
-
purposeId: string,
|
|
531
|
-
// Sent to the legacy Python endpoint only; the ledger resolves the
|
|
532
|
-
// principal from the JWT, so no identifiers are sent in ledger mode.
|
|
533
|
-
contact: string,
|
|
534
|
-
status: 'revoke' | 'regrant' | 'renew',
|
|
535
|
-
authToken?: string,
|
|
536
|
-
options?: Omit<ApiFetchOptions, "getAuthToken">,
|
|
537
|
-
nominatorContact?: string,
|
|
538
|
-
dataElementUuids?: string[],
|
|
539
|
-
productUuid?: string,
|
|
540
|
-
noticeUuid?: string,
|
|
541
|
-
dataElements?: Array<{ uuid: string; selected: boolean }>,
|
|
542
|
-
language?: string
|
|
543
|
-
): Promise<unknown> {
|
|
544
|
-
if (!useLedger()) {
|
|
545
|
-
const url = privacyCenterUrl(baseRequest, `/manage-consent?status=${status}`);
|
|
546
|
-
const body: Record<string, unknown> = { purpose_uuid: purposeId, contact };
|
|
547
|
-
if (nominatorContact) {
|
|
548
|
-
body.nominator_contact = nominatorContact;
|
|
549
|
-
}
|
|
550
|
-
if (Array.isArray(dataElementUuids) && dataElementUuids.length > 0) {
|
|
551
|
-
body.data_element_uuids = dataElementUuids;
|
|
552
|
-
}
|
|
553
|
-
if (productUuid) {
|
|
554
|
-
body.product_uuid = productUuid;
|
|
555
|
-
}
|
|
556
|
-
if (language) {
|
|
557
|
-
body.language = language;
|
|
558
|
-
}
|
|
559
|
-
return privacyCenterApiFetch(url, {
|
|
560
|
-
...options,
|
|
561
|
-
method: "POST",
|
|
562
|
-
body: JSON.stringify(body),
|
|
563
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
564
|
-
});
|
|
565
|
-
}
|
|
566
|
-
if (!noticeUuid) {
|
|
567
|
-
throw new Error("notice_uuid is required to manage consent via the ledger");
|
|
568
|
-
}
|
|
569
|
-
const purposeSelected = status !== 'revoke';
|
|
570
|
-
const elements = (dataElements ?? []).map((de) => {
|
|
571
|
-
let selected: boolean;
|
|
572
|
-
if (status === 'revoke') {
|
|
573
|
-
selected = false;
|
|
574
|
-
} else if (status === 'regrant') {
|
|
575
|
-
// Only the data elements the user chose to re-grant become selected.
|
|
576
|
-
selected = Array.isArray(dataElementUuids)
|
|
577
|
-
? dataElementUuids.includes(de.uuid)
|
|
578
|
-
: de.selected;
|
|
579
|
-
} else {
|
|
580
|
-
// renew — preserve the currently-granted set.
|
|
581
|
-
selected = de.selected;
|
|
582
|
-
}
|
|
583
|
-
return { uuid: de.uuid, selected };
|
|
584
|
-
});
|
|
585
|
-
const body: Record<string, unknown> = {
|
|
586
|
-
notice_uuid: noticeUuid,
|
|
587
|
-
partial: true,
|
|
588
|
-
declined: false,
|
|
589
|
-
select_all_mandatory: false,
|
|
590
|
-
self_declared_adult: false,
|
|
591
|
-
purposes: [
|
|
592
|
-
{
|
|
593
|
-
purpose_uuid: purposeId,
|
|
594
|
-
selected: purposeSelected,
|
|
595
|
-
data_elements: elements,
|
|
596
|
-
},
|
|
597
|
-
],
|
|
598
|
-
...(language ? { language } : {}),
|
|
599
|
-
};
|
|
600
|
-
const url = ledgerUrl(baseRequest, "/submit-consent");
|
|
601
|
-
return privacyCenterApiFetch(url, {
|
|
602
|
-
...options,
|
|
603
|
-
method: "POST",
|
|
604
|
-
body: JSON.stringify(body),
|
|
605
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
606
|
-
});
|
|
607
|
-
},
|
|
608
|
-
|
|
609
|
-
/**
|
|
610
|
-
* Get activities (privacy center)
|
|
611
|
-
*/
|
|
612
|
-
async getActivities(
|
|
613
|
-
baseRequest: BaseRequest,
|
|
614
|
-
offset?: number,
|
|
615
|
-
limit?: number,
|
|
616
|
-
language?: string,
|
|
617
|
-
authToken?: string,
|
|
618
|
-
options?: Omit<ApiFetchOptions, "getAuthToken">
|
|
619
|
-
): Promise<unknown> {
|
|
620
|
-
const queryParams = new URLSearchParams();
|
|
621
|
-
if (offset !== undefined) queryParams.append("offset", offset.toString());
|
|
622
|
-
if (limit !== undefined) queryParams.append("limit", limit.toString());
|
|
623
|
-
if (language) queryParams.append("language", language);
|
|
624
|
-
// Sandbox mode: the acting identity travels as query params
|
|
625
|
-
// (primary_email / primary_mobile); the credential is the X-Consent-Token header.
|
|
626
|
-
appendSandboxIdentity(queryParams);
|
|
627
|
-
const queryString = queryParams.toString();
|
|
628
|
-
const url = privacyCenterUrl(baseRequest, `/activities${queryString ? `?${queryString}` : ""}`);
|
|
629
|
-
return privacyCenterApiFetch<unknown>(url, {
|
|
630
|
-
...options,
|
|
631
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
632
|
-
});
|
|
633
|
-
},
|
|
634
|
-
|
|
635
|
-
/**
|
|
636
|
-
* List all data principals that share this session's contact
|
|
637
|
-
* (shared-contact profile picker). Identity is derived server-side from the
|
|
638
|
-
* JWT — the caller sends nothing but its bearer token.
|
|
639
|
-
*/
|
|
640
|
-
async listIdentities(
|
|
641
|
-
baseRequest: BaseRequest,
|
|
642
|
-
authToken?: string,
|
|
643
|
-
options?: Omit<ApiFetchOptions, "getAuthToken">
|
|
644
|
-
): Promise<IdentityListResponse> {
|
|
645
|
-
const url = privacyCenterUrl(baseRequest, '/identities');
|
|
646
|
-
return privacyCenterApiFetch<IdentityListResponse>(url, {
|
|
647
|
-
...options,
|
|
648
|
-
cache: 'no-store',
|
|
649
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
650
|
-
});
|
|
651
|
-
},
|
|
652
|
-
|
|
653
|
-
/**
|
|
654
|
-
* Re-scope the session to a chosen principal uuid (must be one of the
|
|
655
|
-
* principals sharing this session's contact). Returns fresh access/refresh
|
|
656
|
-
* tokens scoped to that principal.
|
|
657
|
-
*/
|
|
658
|
-
async selectPrincipal(
|
|
659
|
-
baseRequest: BaseRequest,
|
|
660
|
-
principalUuid: string,
|
|
661
|
-
authToken?: string,
|
|
662
|
-
options?: Omit<ApiFetchOptions, "getAuthToken">
|
|
663
|
-
): Promise<SelectPrincipalResponse> {
|
|
664
|
-
const url = privacyCenterUrl(baseRequest, '/identities/select');
|
|
665
|
-
return privacyCenterApiFetch<SelectPrincipalResponse>(url, {
|
|
666
|
-
...options,
|
|
667
|
-
method: 'POST',
|
|
668
|
-
body: JSON.stringify({ uuid: principalUuid }),
|
|
669
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
670
|
-
});
|
|
671
|
-
},
|
|
672
|
-
|
|
673
|
-
/**
|
|
674
|
-
* Get receipts (privacy center) — consent receipts for the authenticated user
|
|
675
|
-
*/
|
|
676
|
-
async getReceipts(
|
|
677
|
-
baseRequest: BaseRequest,
|
|
678
|
-
params: {
|
|
679
|
-
skip?: number;
|
|
680
|
-
limit?: number;
|
|
681
|
-
notice_uuid?: string;
|
|
682
|
-
event_type?: string;
|
|
683
|
-
status?: string;
|
|
684
|
-
created_after?: string;
|
|
685
|
-
created_before?: string;
|
|
686
|
-
language?: string;
|
|
687
|
-
},
|
|
688
|
-
authToken?: string,
|
|
689
|
-
options?: Omit<ApiFetchOptions, "getAuthToken">
|
|
690
|
-
): Promise<unknown> {
|
|
691
|
-
const queryParams = new URLSearchParams();
|
|
692
|
-
if (params.skip !== undefined) queryParams.append("skip", params.skip.toString());
|
|
693
|
-
if (params.limit !== undefined) queryParams.append("limit", params.limit.toString());
|
|
694
|
-
if (params.notice_uuid) queryParams.append("notice_uuid", params.notice_uuid);
|
|
695
|
-
if (params.event_type) queryParams.append("event_type", params.event_type);
|
|
696
|
-
if (params.status) queryParams.append("status", params.status);
|
|
697
|
-
if (params.created_after) queryParams.append("created_after", params.created_after);
|
|
698
|
-
if (params.created_before) queryParams.append("created_before", params.created_before);
|
|
699
|
-
if (params.language) queryParams.append("language", params.language);
|
|
700
|
-
const queryString = queryParams.toString();
|
|
701
|
-
// With a ledger configured, receipts are served by the Go ledger
|
|
702
|
-
// (paginated list under /public/...); otherwise the legacy Python
|
|
703
|
-
// privacy-center list is used. normalizeReceipts tolerates both envelopes.
|
|
704
|
-
const receiptsSuffix = `/receipts${queryString ? `?${queryString}` : ""}`;
|
|
705
|
-
const url = useLedger()
|
|
706
|
-
? ledgerUrl(baseRequest, receiptsSuffix)
|
|
707
|
-
: privacyCenterUrl(baseRequest, receiptsSuffix);
|
|
708
|
-
return privacyCenterApiFetch<unknown>(url, {
|
|
709
|
-
...options,
|
|
710
|
-
method: "GET",
|
|
711
|
-
cache: "no-store",
|
|
712
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
713
|
-
});
|
|
714
|
-
},
|
|
715
|
-
|
|
716
|
-
/**
|
|
717
|
-
* Download a single receipt as a PDF (privacy center).
|
|
718
|
-
* Returns raw PDF bytes as a Blob — the caller builds an object URL to open/save it.
|
|
719
|
-
* Uses a direct fetch (not privacyCenterApiFetch) because the response is binary, not JSON,
|
|
720
|
-
* and the Authorization header must be sent (anchor navigation wouldn't carry it).
|
|
721
|
-
*/
|
|
722
|
-
async getReceiptPdf(
|
|
723
|
-
baseRequest: BaseRequest,
|
|
724
|
-
receiptUuid: string,
|
|
725
|
-
authToken?: string
|
|
726
|
-
): Promise<Blob> {
|
|
727
|
-
// The ledger serves the receipt PDF at /receipts/{uuid}/download, the
|
|
728
|
-
// legacy Python service at /receipts/{uuid}/pdf. The receiptUuid always
|
|
729
|
-
// comes from the same-mode list above, so list and download stay consistent.
|
|
730
|
-
const url = useLedger()
|
|
731
|
-
? ledgerUrl(baseRequest, `/receipts/${receiptUuid}/download`)
|
|
732
|
-
: privacyCenterUrl(baseRequest, `/receipts/${receiptUuid}/pdf`);
|
|
733
|
-
const token = resolveAuthToken(authToken, baseRequest);
|
|
734
|
-
const requestHeaders = new Headers();
|
|
735
|
-
requestHeaders.set("Accept", "application/pdf");
|
|
736
|
-
// Sandbox PoC: send the single X-Consent-Token header instead of the JWT
|
|
737
|
-
// bearer. The receipt PDF download identifies the principal by receiptUuid
|
|
738
|
-
// (already scoped to the sandbox subject via the same-mode list), so no
|
|
739
|
-
// extra identity payload is needed here.
|
|
740
|
-
const sandboxHeaders = sandboxAuthHeaders();
|
|
741
|
-
if (sandboxHeaders) {
|
|
742
|
-
Object.entries(sandboxHeaders).forEach(([key, value]) => {
|
|
743
|
-
requestHeaders.set(key, value);
|
|
744
|
-
});
|
|
745
|
-
} else if (token) {
|
|
746
|
-
const trimmedToken = token.trim();
|
|
747
|
-
requestHeaders.set(
|
|
748
|
-
"Authorization",
|
|
749
|
-
trimmedToken.startsWith("Bearer ") ? trimmedToken : `Bearer ${trimmedToken}`
|
|
750
|
-
);
|
|
751
|
-
}
|
|
752
|
-
const response = await fetch(url, { method: "GET", headers: requestHeaders });
|
|
753
|
-
if (!response.ok) {
|
|
754
|
-
let errorMessage = `Request failed with status ${response.status}`;
|
|
755
|
-
try {
|
|
756
|
-
const errorData = (await response.json()) as { detail?: unknown; error_code?: string } | null;
|
|
757
|
-
if (errorData?.detail) {
|
|
758
|
-
errorMessage =
|
|
759
|
-
typeof errorData.detail === "string" ? errorData.detail : JSON.stringify(errorData.detail);
|
|
760
|
-
} else if (errorData?.error_code) {
|
|
761
|
-
errorMessage = errorData.error_code;
|
|
762
|
-
}
|
|
763
|
-
} catch {
|
|
764
|
-
// non-JSON error body — keep default message
|
|
765
|
-
}
|
|
766
|
-
// Prepend HTTP status so callers can branch on it (e.g. 404 = receipt not found)
|
|
767
|
-
throw new Error(`[${response.status}] ${errorMessage}`);
|
|
768
|
-
}
|
|
769
|
-
return response.blob();
|
|
770
|
-
},
|
|
771
|
-
|
|
772
|
-
/**
|
|
773
|
-
* Get case history (privacy center)
|
|
774
|
-
*/
|
|
775
|
-
async getCaseHistory(
|
|
776
|
-
baseRequest: BaseRequest,
|
|
777
|
-
_contact: string,
|
|
778
|
-
offset?: number,
|
|
779
|
-
limit?: number,
|
|
780
|
-
language?: string,
|
|
781
|
-
authToken?: string,
|
|
782
|
-
options?: Omit<ApiFetchOptions, "getAuthToken">
|
|
783
|
-
): Promise<unknown> {
|
|
784
|
-
const queryParams = new URLSearchParams();
|
|
785
|
-
if (offset !== undefined) queryParams.append("offset", offset.toString());
|
|
786
|
-
if (limit !== undefined) queryParams.append("limit", limit.toString());
|
|
787
|
-
if (language) queryParams.append("language", language);
|
|
788
|
-
// Sandbox mode: the acting identity travels as query params
|
|
789
|
-
// (primary_email / primary_mobile); the credential is the X-Consent-Token header.
|
|
790
|
-
appendSandboxIdentity(queryParams);
|
|
791
|
-
const queryString = queryParams.toString();
|
|
792
|
-
const url = privacyCenterUrl(baseRequest, `/cases?${queryString}`);
|
|
793
|
-
return privacyCenterApiFetch<unknown>(url, {
|
|
794
|
-
...options,
|
|
795
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
796
|
-
});
|
|
797
|
-
},
|
|
798
|
-
|
|
799
|
-
// ─── Case Communication ─────────────────────────────────────────────────
|
|
800
|
-
|
|
801
|
-
/**
|
|
802
|
-
* Get messages for a case (privacy center)
|
|
803
|
-
*/
|
|
804
|
-
async getCaseMessages(
|
|
805
|
-
baseRequest: BaseRequest,
|
|
806
|
-
caseUuid: string,
|
|
807
|
-
authToken?: string
|
|
808
|
-
): Promise<CaseMessage[]> {
|
|
809
|
-
// Sandbox mode: the acting identity travels as query params
|
|
810
|
-
// (primary_email / primary_mobile); the credential is the X-Consent-Token header.
|
|
811
|
-
const url = caseUrl(baseRequest, caseUuid, `/messages${sandboxIdentitySuffix()}`);
|
|
812
|
-
return privacyCenterApiFetch<CaseMessage[]>(url, {
|
|
813
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
814
|
-
});
|
|
815
|
-
},
|
|
816
|
-
|
|
817
|
-
/**
|
|
818
|
-
* Send a message on a case (privacy center)
|
|
819
|
-
*/
|
|
820
|
-
async sendCaseMessage(
|
|
821
|
-
baseRequest: BaseRequest,
|
|
822
|
-
caseUuid: string,
|
|
823
|
-
body: string,
|
|
824
|
-
documentUuids: string[],
|
|
825
|
-
authToken?: string
|
|
826
|
-
): Promise<CaseMessage> {
|
|
827
|
-
// Sandbox mode: the acting identity travels as query params
|
|
828
|
-
// (primary_email / primary_mobile); the credential is the X-Consent-Token header.
|
|
829
|
-
const url = caseUrl(baseRequest, caseUuid, `/messages${sandboxIdentitySuffix()}`);
|
|
830
|
-
return privacyCenterApiFetch<CaseMessage>(url, {
|
|
831
|
-
method: 'POST',
|
|
832
|
-
body: JSON.stringify({ body, document_uuids: documentUuids }),
|
|
833
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
834
|
-
});
|
|
835
|
-
},
|
|
836
|
-
|
|
837
|
-
/**
|
|
838
|
-
* Upload a document on a case (multipart/form-data, privacy center)
|
|
839
|
-
*/
|
|
840
|
-
async uploadCaseDocument(
|
|
841
|
-
baseRequest: BaseRequest,
|
|
842
|
-
caseUuid: string,
|
|
843
|
-
file: File,
|
|
844
|
-
authToken?: string
|
|
845
|
-
): Promise<UploadDocumentResponse> {
|
|
846
|
-
// Sandbox mode: the acting identity travels as query params
|
|
847
|
-
// (primary_email / primary_mobile); the credential is the X-Consent-Token header.
|
|
848
|
-
const url = caseUrl(baseRequest, caseUuid, `/upload-document${sandboxIdentitySuffix()}`);
|
|
849
|
-
const formData = new FormData();
|
|
850
|
-
formData.append('file', file, file.name); // field name must be exactly "file"
|
|
851
|
-
// "payload" is required by the privacy-center endpoint (omitting it causes 422)
|
|
852
|
-
formData.append('payload', JSON.stringify({ metadata: null }));
|
|
853
|
-
return privacyCenterApiFetch<UploadDocumentResponse>(url, {
|
|
854
|
-
method: 'POST',
|
|
855
|
-
body: formData,
|
|
856
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
857
|
-
});
|
|
858
|
-
},
|
|
859
|
-
|
|
860
|
-
/**
|
|
861
|
-
* Submit a document against a handler document request (privacy center)
|
|
862
|
-
*/
|
|
863
|
-
async submitDocumentForRequest(
|
|
864
|
-
baseRequest: BaseRequest,
|
|
865
|
-
caseUuid: string,
|
|
866
|
-
requestEventUuid: string,
|
|
867
|
-
documentUuid: string,
|
|
868
|
-
body: string,
|
|
869
|
-
authToken?: string
|
|
870
|
-
): Promise<CaseMessage> {
|
|
871
|
-
const url = caseUrl(baseRequest, caseUuid, `/document-requests/${requestEventUuid}/submit`);
|
|
872
|
-
return privacyCenterApiFetch<CaseMessage>(url, {
|
|
873
|
-
method: 'POST',
|
|
874
|
-
body: JSON.stringify({ document_uuid: documentUuid, body }),
|
|
875
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
876
|
-
});
|
|
877
|
-
},
|
|
878
|
-
|
|
879
|
-
/**
|
|
880
|
-
* Get document info/download URL for a case document (privacy center)
|
|
881
|
-
*/
|
|
882
|
-
async getCaseDocument(
|
|
883
|
-
baseRequest: BaseRequest,
|
|
884
|
-
caseUuid: string,
|
|
885
|
-
documentUuid: string,
|
|
886
|
-
authToken?: string
|
|
887
|
-
): Promise<MessageDocument> {
|
|
888
|
-
const url = caseUrl(baseRequest, caseUuid, `/documents/${documentUuid}`);
|
|
889
|
-
return privacyCenterApiFetch<MessageDocument>(url, {
|
|
890
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
891
|
-
});
|
|
892
|
-
},
|
|
893
|
-
|
|
894
|
-
// ─── Notification Hub ─────────────────────────────────────────────────
|
|
895
|
-
|
|
896
|
-
/**
|
|
897
|
-
* List notifications (paginated, with filters)
|
|
898
|
-
*/
|
|
899
|
-
async getNotifications(
|
|
900
|
-
baseRequest: BaseRequest,
|
|
901
|
-
params?: NotificationQueryParams,
|
|
902
|
-
authToken?: string
|
|
903
|
-
): Promise<NotificationListResponse> {
|
|
904
|
-
const queryParams = new URLSearchParams();
|
|
905
|
-
if (params?.category) {
|
|
906
|
-
queryParams.append('category', params.category);
|
|
907
|
-
}
|
|
908
|
-
if (params?.notification_type) {
|
|
909
|
-
queryParams.append('notification_type', params.notification_type);
|
|
910
|
-
}
|
|
911
|
-
if (params?.is_read !== undefined) {
|
|
912
|
-
queryParams.append('is_read', String(params.is_read));
|
|
913
|
-
}
|
|
914
|
-
if (params?.skip !== undefined) {
|
|
915
|
-
queryParams.append('skip', params.skip.toString());
|
|
916
|
-
}
|
|
917
|
-
if (params?.limit !== undefined) {
|
|
918
|
-
queryParams.append('limit', params.limit.toString());
|
|
919
|
-
}
|
|
920
|
-
if (params?.include_summary) {
|
|
921
|
-
queryParams.append('include_summary', 'true');
|
|
922
|
-
}
|
|
923
|
-
if (params?.language) {
|
|
924
|
-
queryParams.append('language', params.language);
|
|
925
|
-
}
|
|
926
|
-
const queryString = queryParams.toString();
|
|
927
|
-
const url = notificationUrl(baseRequest, queryString ? `?${queryString}` : '');
|
|
928
|
-
return privacyCenterApiFetch<NotificationListResponse>(url, {
|
|
929
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
930
|
-
});
|
|
931
|
-
},
|
|
932
|
-
|
|
933
|
-
/**
|
|
934
|
-
* Get notification summary (aggregated counts only)
|
|
935
|
-
*/
|
|
936
|
-
async getNotificationSummary(
|
|
937
|
-
baseRequest: BaseRequest,
|
|
938
|
-
authToken?: string
|
|
939
|
-
): Promise<NotificationSummary> {
|
|
940
|
-
const url = notificationUrl(baseRequest, '/summary');
|
|
941
|
-
return privacyCenterApiFetch<NotificationSummary>(url, {
|
|
942
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
943
|
-
});
|
|
944
|
-
},
|
|
945
|
-
|
|
946
|
-
/**
|
|
947
|
-
* Get unread notification count (lightweight, for badge)
|
|
948
|
-
*/
|
|
949
|
-
async getUnreadCount(
|
|
950
|
-
baseRequest: BaseRequest,
|
|
951
|
-
authToken?: string
|
|
952
|
-
): Promise<UnreadCountResponse> {
|
|
953
|
-
const url = notificationUrl(baseRequest, '/unread-count');
|
|
954
|
-
return privacyCenterApiFetch<UnreadCountResponse>(url, {
|
|
955
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
956
|
-
});
|
|
957
|
-
},
|
|
958
|
-
|
|
959
|
-
/**
|
|
960
|
-
* Mark a single notification as read
|
|
961
|
-
*/
|
|
962
|
-
async markNotificationRead(
|
|
963
|
-
baseRequest: BaseRequest,
|
|
964
|
-
notificationUuid: string,
|
|
965
|
-
authToken?: string
|
|
966
|
-
): Promise<NotificationActionResponse> {
|
|
967
|
-
const url = notificationUrl(baseRequest, `/${notificationUuid}/read`);
|
|
968
|
-
return privacyCenterApiFetch<NotificationActionResponse>(url, {
|
|
969
|
-
method: 'PATCH',
|
|
970
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
971
|
-
});
|
|
972
|
-
},
|
|
973
|
-
|
|
974
|
-
/**
|
|
975
|
-
* Mark all notifications as read
|
|
976
|
-
*/
|
|
977
|
-
async markAllNotificationsRead(
|
|
978
|
-
baseRequest: BaseRequest,
|
|
979
|
-
authToken?: string
|
|
980
|
-
): Promise<NotificationActionResponse> {
|
|
981
|
-
const url = notificationUrl(baseRequest, '/mark-all-read');
|
|
982
|
-
return privacyCenterApiFetch<NotificationActionResponse>(url, {
|
|
983
|
-
method: 'POST',
|
|
984
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
985
|
-
});
|
|
986
|
-
},
|
|
987
|
-
|
|
988
|
-
/**
|
|
989
|
-
* Acknowledge a notification (sets is_read and is_acknowledged to true)
|
|
990
|
-
*/
|
|
991
|
-
async acknowledgeNotification(
|
|
992
|
-
baseRequest: BaseRequest,
|
|
993
|
-
notificationUuid: string,
|
|
994
|
-
authToken?: string
|
|
995
|
-
): Promise<NotificationActionResponse> {
|
|
996
|
-
const url = notificationUrl(baseRequest, `/${notificationUuid}/acknowledge`);
|
|
997
|
-
return privacyCenterApiFetch<NotificationActionResponse>(url, {
|
|
998
|
-
method: 'POST',
|
|
999
|
-
authToken: resolveAuthToken(authToken, baseRequest),
|
|
1000
|
-
});
|
|
1001
|
-
},
|
|
1002
|
-
};
|
|
1003
|
-
}
|