@tantainnovative/ndpr-toolkit
Version:
Nigeria Data Protection Toolkit — enterprise-grade compliance components for the Nigeria Data Protection Act (NDPA) 2023
1,321 lines (1,244 loc) • 100 kB
text/typescript
import { ErrorInfo } from 'react';
import React__default from 'react';
import { ReactNode } from 'react';
/**
* Adequacy status of a destination country
*/
export declare type AdequacyStatus = 'adequate' | 'inadequate' | 'pending_review' | 'unknown';
/**
* Appends a single audit entry to the consent audit log in localStorage.
* The log is append-only; existing entries are never modified.
*
* @param entry - The audit entry to append
* @param storageKey - Base storage key (the audit key is derived as `${storageKey}_audit`)
*/
export declare function appendAuditEntry(entry: ConsentAuditEntry, storageKey?: string): void;
export declare const arabicLocale: Required<{
[K in keyof NDPRLocale]: Required<NonNullable<NDPRLocale[K]>>;
}>;
/**
* Assemble an ordered, NDPA-aligned array of privacy-policy sections from
* a {@link TemplateContext}. This is the canonical "compute the policy"
* function — it produces structured `PolicySection[]` data that downstream
* renderers (`exportHTML`, `exportMarkdown`, `exportPDF`, `exportDOCX`,
* `<PolicyPage />`) consume.
*
* Section composition:
* - **Core sections** (always included): Introduction, Data Collection,
* Legal Basis, Data Usage, Data Sharing, Data Retention, Data Security,
* Data Subject Rights, Contact Information.
* - **Conditional sections** (included based on context flags):
* - `hasChildrenData` → Children's Data Protection (NDPA §31)
* - `hasSensitiveData` → Sensitive / Special-Category Data
* - `hasCrossBorderTransfer` → Cross-Border Transfers (NDPA Part VI)
* - `hasAutomatedDecisions` → Automated Decision-Making (NDPA §37)
*
* Section text uses `«TODO: fieldName»` markers (the `UNFILLED_PREFIX` constant)
* for any required org-info field that's empty in the context. Pair with
* {@link findUnfilledTokens} to surface those before publishing.
*
* @param context - Organisation info, data categories, processing purposes,
* third-party processors, and feature flags. Build a default
* context with `createDefaultContext()` then mutate.
* @returns An ordered array of {@link PolicySection} objects ready to pass
* to `exportHTML(policy)` or `<PolicyPage policy={...} />`.
*
* @example
* ```ts
* import { assemblePolicy, createDefaultContext } from '@tantainnovative/ndpr-toolkit/server';
*
* const ctx = createDefaultContext();
* ctx.org.name = 'Acme Nigeria Ltd';
* ctx.org.privacyEmail = 'privacy@acme.ng';
* ctx.hasCrossBorderTransfer = true;
*
* const sections = assemblePolicy(ctx);
* // sections is a 10-element array (9 core + 1 cross-border)
* ```
*/
export declare function assemblePolicy(context: TemplateContext): PolicySection[];
/**
* Assess a breach report against the NDPA S. 40 / GAID 2025 Article 33
* notification requirements.
*/
export declare function assessBreachNotification(report: BreachReport, options?: BreachNotificationOptions): BreachNotificationAssessment;
/**
* Analyzes all processing activities and returns compliance gaps including
* missing DPO approval, overdue reviews, undocumented justifications,
* missing LIA for legitimate interests, and other documentation issues.
*
* @param activities Array of processing activities to analyze
* @returns Array of identified compliance gaps
*/
export declare function assessComplianceGaps(activities: ProcessingActivity[]): LawfulBasisComplianceGap[];
/**
* Assesses the risk level of a DPIA based on the identified risks
* @param dpiaResult The DPIA result containing risks to assess
* @returns Assessment result with overall risk level and recommendations
*/
export declare function assessDPIARisk(dpiaResult: DPIAResult): {
overallRiskLevel: 'low' | 'medium' | 'high' | 'critical';
requiresConsultation: boolean;
canProceed: boolean;
recommendations: string[];
};
/**
* Performs a basic risk assessment of a cross-border transfer based on adequacy status,
* transfer mechanism, and data sensitivity.
*
* @param transfer The cross-border transfer to assess
* @returns Risk assessment result with score, factors, and recommendations
*/
export declare function assessTransferRisk(transfer: CrossBorderTransfer): TransferRiskResult;
export declare interface AuditCheck {
id: string;
label: string;
status: AuditCheckStatus;
detail: string;
}
export declare type AuditCheckStatus = 'pass' | 'warn' | 'fail';
/**
* Breach notification types aligned with NDPA 2023 Section 40
* Data controllers must notify the NDPC within 72 hours of becoming aware of a breach
* Data subjects must be notified without undue delay when breach is likely to result in high risk
*/
/**
* Represents a data breach category
*/
export declare interface BreachCategory {
/** Unique identifier for the category */
id: string;
/** Display name for the category */
name: string;
/** Description of this breach category */
description: string;
/** Default severity level for this category */
defaultSeverity: 'low' | 'medium' | 'high' | 'critical';
}
export declare interface BreachNotificationAssessment {
/** Whether all applicable mandated content items are satisfied. */
complete: boolean;
/** Completeness of applicable content items, 0–100. */
completeness: number;
/** GAID 2025 Article 33(5) / NDPA S. 40(2) content of the notification to the Commission. */
notificationToCommission: BreachNotificationItem[];
/** NDPA S. 40(3) communication to data subjects — populated only when high-risk. */
dataSubjectCommunication: BreachNotificationItem[];
/** Whether a data-subject communication is owed (high risk). */
dataSubjectCommunicationRequired: boolean;
timing: BreachNotificationTiming;
/** Labels of unsatisfied applicable items. */
missing: string[];
/** Actionable next steps, including timing warnings. */
recommendations: string[];
asOf: number;
}
export declare interface BreachNotificationItem {
/** Stable identifier for the requirement. */
id: string;
/** Human-readable requirement. */
label: string;
/** Authoritative citation, e.g. `GAID 2025 Art. 33(5)(a)`. */
section: string;
/** Whether the report satisfies it. */
satisfied: boolean;
}
/**
* Personal-data-breach notification completeness checker for NDPA 2023
* Section 40, as detailed by NDPC General Application and Implementation
* Directive (GAID) 2025 Article 33.
*
* Section 40(2) requires a data controller to notify the Commission within 72
* hours of becoming aware of a breach likely to result in a risk to data
* subjects' rights and freedoms. GAID 2025 Article 33(5)(a)–(h) enumerates the
* content that a notification to the Commission "shall include". Where the
* breach is likely to result in a *high* risk, Section 40(3) additionally
* requires the controller to communicate the breach to affected data subjects
* in plain and clear language.
*
* This assesses a `BreachReport` against those requirements: which mandated
* content items are present, whether the 72-hour window is met, and whether a
* data-subject communication is owed. It is a documentation-completeness aid,
* not legal advice — verify against current NDPC guidance.
*
* @see NDPA 2023 Section 40 (Personal data breaches)
* @see NDPC GAID 2025 Article 33 (Data Breach Notification)
*/
export declare interface BreachNotificationOptions {
/** Risk assessment for the breach; drives whether data-subject communication is required. */
assessment?: RiskAssessment;
/** The regulatory notification actually sent, if any — used to judge timeliness. */
notification?: RegulatoryNotification;
/** Reference "now" in epoch ms. Defaults to `Date.now()`. */
asOf?: number;
/** Notification window in hours. Defaults to 72 (NDPA S. 40(2)). */
deadlineHours?: number;
/**
* Explicit high-risk flag (NDPA S. 40(3)). When omitted, derived from
* `assessment.highRisksToRightsAndFreedoms`.
*/
highRisk?: boolean;
}
export declare interface BreachNotificationTiming {
/** `discoveredAt` + the notification window. */
deadline: number;
/** Whole hours between discovery and `asOf`. */
hoursSinceDiscovery: number;
/** Whether a regulatory notification has been recorded. */
notified: boolean;
/** When the regulatory notification was sent, if any. */
notifiedAt?: number;
/** Whether the notification (or, if none, `asOf`) falls within the deadline. */
withinDeadline: boolean;
/** Whole hours from `asOf` to the deadline (negative once past). */
hoursRemaining: number;
/** Whether the deadline has been missed. */
overdue: boolean;
/** Late filings must state the reasons for the delay (NDPA S. 40(2)). */
requiresDelayJustification: boolean;
}
/**
* Represents a data breach report
*/
export declare interface BreachReport {
/** Unique identifier for the breach report */
id: string;
/** Title/summary of the breach */
title: string;
/** Detailed description of the breach */
description: string;
/** Category of the breach */
category: string;
/** Timestamp when the breach was discovered */
discoveredAt: number;
/** Timestamp when the breach occurred (if known) */
occurredAt?: number;
/** Timestamp when the breach was reported internally */
reportedAt: number;
/** Person who reported the breach */
reporter: {
name: string;
email: string;
department: string;
phone?: string;
};
/** Systems or data affected by the breach */
affectedSystems: string[];
/** Types of data involved in the breach */
dataTypes: string[];
/** Whether sensitive personal data is involved (NDPA Section 30) */
involvesSensitiveData?: boolean;
/** Estimated number of data subjects affected */
estimatedAffectedSubjects?: number;
/**
* Approximate number of personal data RECORDS concerned (distinct from subject count).
* Required content under NDPA Section 40(1)(a) and Section 40(2).
*/
approximateRecordCount?: number;
/**
* Categories of data subjects affected (e.g. customers, employees, minors, patients).
* Required content under NDPA Section 40(1)(a) and Section 40(2).
*/
dataSubjectCategories?: string[];
/**
* Likely consequences of the breach for affected data subjects (e.g. identity theft,
* financial loss, reputational damage). Reported to the NDPC and, where applicable,
* communicated to data subjects under Section 40(3).
*/
likelyConsequences?: string;
/**
* Measures taken or proposed to mitigate adverse effects of the breach.
* Required content for Section 40(3) communications to data subjects.
*/
mitigationMeasures?: string;
/**
* Whether this is a phased / interim report submitted before full investigation
* is complete. The NDPC permits phased reporting where complete information is
* not available within 72 hours.
*/
isPhasedReport?: boolean;
/**
* ID of the prior phased report this report supplements, if any.
*/
supplementsReportId?: string;
/**
* Data Protection Officer contact details. The DPO is the named contact point
* for the NDPC per NDPA Section 32(3)(c). Required content in the regulatory
* report (Section 40(2)).
*/
dpoContact?: {
name: string;
email: string;
phone?: string;
};
/** Whether the breach is ongoing or contained */
status: 'ongoing' | 'contained' | 'resolved';
/** Initial actions taken to address the breach */
initialActions?: string;
/** Attachments related to the breach */
attachments?: Array<{
id: string;
name: string;
type: string;
url: string;
addedAt: number;
}>;
}
/**
* Calculates the severity of a data breach based on various factors
* @param report The breach report
* @param assessment The risk assessment (if available)
* @returns The calculated severity and notification requirements
*/
export declare function calculateBreachSeverity(report: BreachReport, assessment?: RiskAssessment): {
severityLevel: 'low' | 'medium' | 'high' | 'critical';
notificationRequired: boolean;
urgentNotificationRequired: boolean;
timeframeHours: number;
justification: string;
};
/**
* Compliance Audit Returns (CAR) scheduling under the NDPC General Application
* and Implementation Directive (GAID) 2025.
*
* A Data Controller/Processor of Major Importance (DCPMI) must conduct an
* initial compliance audit within 15 months of commencing data processing, and
* thereafter file a Compliance Audit Return with the NDPC annually (default
* deadline 31 March, filed through the NDPC Information Management Portal/NIMP).
*
* This computes the schedule (initial-audit due date, the next annual filing
* deadline relative to a reference date) and a light status. NDPC deadlines
* shift (the 2026 filing was extended to 30 May), so the annual deadline is
* configurable and per-year overrides are supported. The audit *content* itself
* is the organisation's compliance posture — pair this with `getComplianceScore`.
*
* @see NDPC General Application and Implementation Directive (GAID) 2025
*/
export declare interface CARInput {
/** ISO date (YYYY-MM-DD) the organisation commenced data processing. */
commencementDate: string;
/** Reference date to evaluate against (YYYY-MM-DD). Defaults to today. */
asOf?: string;
/** DCPMI tier; CAR applies to DCPMIs only. Omit to assume applicable. */
tier?: DCPMITier;
}
export declare interface CAROptions {
/** Default annual filing deadline (month is 1-12). Defaults to 31 March. */
annualDeadline?: {
month: number;
day: number;
};
/** Per-year overrides for the annual deadline, e.g. `{ 2026: '2026-05-30' }`. */
deadlineOverrides?: Record<number, string>;
/** Months after commencement the initial audit is due. Defaults to 15. */
initialAuditWithinMonths?: number;
}
/**
* Classify an organisation's DCPMI status, registration tier, annual fee, and
* Compliance Audit Returns obligations under NDPC GAID 2025.
*/
export declare function classifyDCPMI(input: DCPMIInput, options?: DCPMIClassificationOptions): DCPMIClassification;
export declare interface ComplianceAuditReturn {
/** Whether CAR applies (false for non-DCPMI organisations). */
applicable: boolean;
schedule: {
commencementDate: string;
initialAuditWithinMonths: number;
/** Commencement date + the initial-audit window. */
initialAuditDueDate: string;
/** The next annual filing deadline on or after `asOf`. */
nextFilingDeadline: string;
/** The year the next filing deadline falls in. */
filingYear: number;
};
status: {
/** Whether the initial-audit obligation has arisen (asOf ≥ due date). */
initialAuditDue: boolean;
/** Whole days from `asOf` to the next filing deadline. */
daysUntilNextDeadline: number;
};
notes: string[];
asOf: string;
}
/** A single gap found during NDPA compliance evaluation. */
export declare interface ComplianceGap {
/** Machine-readable requirement identifier. */
requirementId: string;
/** Human-readable name of the requirement. */
requirement: string;
/** Reference to the relevant NDPA section. */
ndpaSection: string;
/** How severe the gap is. */
severity: 'critical' | 'important' | 'recommended';
/** Explanation of what is missing. */
message: string;
/** Suggested fix type for the UI. */
fixType: 'add_section' | 'add_content' | 'fill_field';
/** Label for the fix action button. */
fixLabel: string;
/** Pre-written content the user can insert to close the gap. */
suggestedContent?: string;
}
export declare interface ComplianceInput {
consent: {
hasConsentMechanism: boolean;
hasPurposeSpecification: boolean;
hasWithdrawalMechanism: boolean;
hasMinorProtection: boolean;
consentRecordsRetained: boolean;
};
dsr: {
hasRequestMechanism: boolean;
supportsAccess: boolean;
supportsRectification: boolean;
supportsErasure: boolean;
supportsPortability: boolean;
supportsObjection: boolean;
/** Expected max response time in days (>30 counts as a gap) */
responseTimelineDays: number;
};
dpia: {
conductedForHighRisk: boolean;
documentedRisks: boolean;
mitigationMeasures: boolean;
};
breach: {
hasNotificationProcess: boolean;
notifiesWithin72Hours: boolean;
hasRiskAssessment: boolean;
hasRecordKeeping: boolean;
};
policy: {
hasPrivacyPolicy: boolean;
isPubliclyAccessible: boolean;
/** ISO date string (YYYY-MM-DD); >13 months old counts as a gap */
lastUpdated: string;
coversAllSections: boolean;
};
lawfulBasis: {
documentedForAllProcessing: boolean;
hasLegitimateInterestAssessment: boolean;
};
crossBorder: {
hasTransferMechanisms: boolean;
adequacyAssessed: boolean;
ndpcApprovalObtained: boolean;
};
ropa: {
maintained: boolean;
includesAllProcessing: boolean;
/** ISO date string (YYYY-MM-DD); >6 months since review counts as a gap */
lastReviewed: string;
};
}
/**
* Compliance Score Engine
*
* Evaluates an organisation's NDPA compliance posture across eight modules and
* returns a scored, rated report with per-module breakdowns and sorted
* recommendations.
*
* Pure utility — zero React dependency.
*/
export declare type ComplianceRating = 'excellent' | 'good' | 'needs-work' | 'critical';
export declare interface ComplianceReport {
/** Overall compliance score, 0–100 */
score: number;
/** Rating bucket */
rating: ComplianceRating;
/** Per-module breakdown keyed by module name */
modules: Record<string, ModuleScore>;
/** Recommendations sorted by priority (critical first) */
recommendations: Recommendation[];
/** Top-level regulatory references */
regulatoryReferences: RegulatoryReference[];
/** ISO date of when the report was generated */
generatedAt: string;
}
/** Result of evaluating a policy against NDPA requirements. */
export declare interface ComplianceResult {
/** Points earned. */
score: number;
/** Maximum achievable points (115). */
maxScore: number;
/** Percentage score (0-100). */
percentage: number;
/** Overall compliance rating. */
rating: 'compliant' | 'nearly_compliant' | 'not_compliant';
/** List of identified compliance gaps. */
gaps: ComplianceGap[];
/** List of requirement ids that passed. */
passed: string[];
}
/**
* Represents a single entry in the consent audit trail.
* Each entry captures what happened, when, and the full consent state
* at that point in time, satisfying NDPA recordkeeping requirements.
*/
export declare interface ConsentAuditEntry {
/** The type of consent action that occurred */
action: 'consent_given' | 'consent_withdrawn' | 'consent_updated' | 'consent_expired';
/** Unix timestamp (ms) when the action occurred */
timestamp: number;
/** Version of the consent form at the time of the action */
version: string;
/** Full snapshot of consent category states */
categories: Record<string, boolean>;
/** How consent was collected (e.g. "banner", "customize", "api") */
method: string;
/** Browser user-agent string for forensic traceability */
userAgent?: string;
}
/**
* Consent types aligned with NDPA 2023 Section 25-26
* Consent must be freely given, specific, informed, and unambiguous
*/
/**
* Represents a consent option that can be presented to users
*/
export declare interface ConsentOption {
/** Unique identifier for the consent option */
id: string;
/** Display label for the consent option */
label: string;
/** Detailed description of what this consent option covers */
description: string;
/** Whether this consent option is required (cannot be declined) */
required: boolean;
/**
* The specific purpose for which data will be processed
* NDPA Section 25(2) requires consent to be specific to each purpose
*/
purpose: string;
/**
* Default state of the consent option
* @default false
*/
defaultValue?: boolean;
/**
* Categories of personal data covered by this consent option
*/
dataCategories?: string[];
}
/**
* Represents the user's consent settings
*/
export declare interface ConsentSettings {
/** Map of consent option IDs to boolean values indicating consent status */
consents: Record<string, boolean>;
/** Timestamp when consent was last updated */
timestamp: number;
/** Version of the consent form that was accepted */
version: string;
/** Method used to collect consent (e.g., "banner", "settings", "api") */
method: string;
/** Whether the user has actively made a choice (as opposed to default settings) */
hasInteracted: boolean;
/**
* The lawful basis under which processing is conducted
* Required by NDPA Section 25(1)
*/
lawfulBasis?: LawfulBasisType;
}
/**
* Represents the storage mechanism for consent settings
*/
export declare interface ConsentStorageOptions {
/**
* Storage key for consent settings
* @default "ndpr_consent"
*/
storageKey?: string;
/**
* Storage type to use
* @default "localStorage"
*/
storageType?: 'localStorage' | 'sessionStorage' | 'cookie';
/**
* Cookie options (only used when storageType is "cookie")
*/
cookieOptions?: {
/** Domain for the cookie */
domain?: string;
/**
* Path for the cookie
* @default "/"
*/
path?: string;
/**
* Expiration days for the cookie
* @default 365
*/
expires?: number;
/**
* Whether the cookie should be secure
* @default true
*/
secure?: boolean;
/**
* SameSite attribute for the cookie
* @default "Lax"
*/
sameSite?: 'Strict' | 'Lax' | 'None';
};
}
/** How a present cookie was classified. */
export declare type CookieMatchSource = 'declared' | 'known' | 'none';
export declare interface CookieScanOptions {
/**
* The cookie string to scan, in `document.cookie` form (`a=1; b=2`).
* Defaults to `document.cookie` in the browser, or `''` on the server.
*/
cookieString?: string;
/** Reference timestamp (epoch ms) recorded on the result. Defaults to `Date.now()`. */
asOf?: number;
/** Extra known cookies, checked before the built-in registry (so they can override it). */
knownCookies?: DeclaredCookie[];
/** Whether to fall back to the built-in known-cookie registry for undeclared cookies. @default true */
useKnownRegistry?: boolean;
}
export declare interface CookieScanResult {
/** When the scan ran (epoch ms). */
scannedAt: number;
/** Number of cookies present. */
total: number;
/** Every present cookie, classified. */
cookies: ScannedCookie[];
/** Cookies that matched one of your declared cookies. */
declared: ScannedCookie[];
/** Cookies present but NOT in your declaration — the compliance gap. */
undeclared: ScannedCookie[];
/** Undeclared cookies the built-in registry could still identify. */
identified: ScannedCookie[];
/** Undeclared cookies that could not be identified at all. */
unknown: ScannedCookie[];
/** Present cookies grouped by resolved category; unclassified cookies go under `uncategorized`. */
byCategory: Record<string, ScannedCookie[]>;
/** True when there are no undeclared cookies. */
complete: boolean;
}
/**
* Creates a new audit entry from consent settings. If `previousSettings` is
* provided, the action is automatically determined by comparing old and new
* states. Otherwise `action` defaults to `'consent_given'`.
*/
export declare function createAuditEntry(settings: ConsentSettings, previousSettings?: ConsentSettings | null, actionOverride?: ConsentAuditEntry['action']): ConsentAuditEntry;
/**
* Creates a complete business privacy policy template with default
* NDPA-compliant sections and variables.
*
* @returns An object containing the default sections and variables.
*/
export declare function createBusinessPolicyTemplate(): {
sections: PolicySection[];
variables: PolicyVariable[];
};
/**
* Creates a default TemplateContext with sensible empty/initial values.
* Useful for initialising the wizard state before the user begins editing.
*/
export declare function createDefaultContext(): TemplateContext;
/**
* Summary of cross-border transfer compliance
*/
export declare interface CrossBorderSummary {
/** Total number of active transfers */
totalActiveTransfers: number;
/** Breakdown by transfer mechanism */
byMechanism: Record<TransferMechanism, number>;
/** Breakdown by adequacy status */
byAdequacy: Record<AdequacyStatus, number>;
/** Transfers pending NDPC approval */
pendingApproval: CrossBorderTransfer[];
/** Transfers due for review */
dueForReview: CrossBorderTransfer[];
/** Transfers missing TIA */
missingTIA: CrossBorderTransfer[];
/** High-risk transfers */
highRiskTransfers: CrossBorderTransfer[];
/** Last updated timestamp */
lastUpdated: number;
}
/**
* Represents a cross-border data transfer record
*/
export declare interface CrossBorderTransfer {
/** Unique identifier */
id: string;
/** Destination country or territory */
destinationCountry: string;
/** ISO country code */
destinationCountryCode?: string;
/** Adequacy status of the destination */
adequacyStatus: AdequacyStatus;
/** The transfer mechanism being relied upon */
transferMechanism: TransferMechanism;
/** Categories of personal data being transferred */
dataCategories: string[];
/** Whether sensitive personal data is included */
includesSensitiveData: boolean;
/** Estimated number of data subjects whose data is transferred */
estimatedDataSubjects?: number;
/** Name of the recipient organization */
recipientOrganization: string;
/** Contact details of the recipient */
recipientContact: {
name: string;
email: string;
phone?: string;
address?: string;
};
/** Purpose of the data transfer */
purpose: string;
/** Safeguards in place to protect the data */
safeguards: string[];
/** Risk assessment summary */
riskAssessment: string;
/** Risk level of the transfer */
riskLevel: 'low' | 'medium' | 'high';
/** NDPC approval details (required for some transfer mechanisms) */
ndpcApproval?: {
required: boolean;
applied: boolean;
approved?: boolean;
referenceNumber?: string;
appliedAt?: number;
approvedAt?: number;
};
/** Whether a Transfer Impact Assessment has been conducted */
tiaCompleted: boolean;
/** Reference to the TIA document */
tiaReference?: string;
/** Frequency of the transfer */
frequency: 'one_time' | 'periodic' | 'continuous';
/** Start date of the transfer */
startDate: number;
/** End date of the transfer (if applicable) */
endDate?: number;
/** Status of the transfer */
status: 'active' | 'suspended' | 'terminated' | 'pending_approval';
/** Timestamp when the record was created */
createdAt: number;
/** Timestamp when the record was last updated */
updatedAt: number;
/** Next review date */
reviewDate?: number;
}
/** A user-defined section added to the policy outside the generated ones. */
export declare interface CustomSection {
id: string;
title: string;
content: string;
order: number;
required: false;
}
/** A logical category of personal data the organisation may collect. */
export declare interface DataCategory {
/** Machine-readable identifier. */
id: string;
/** Human-readable label shown in the wizard. */
label: string;
/** Grouping for display and compliance checks. */
group: 'identity' | 'financial' | 'behavioral' | 'sensitive' | 'children';
/** Specific data points within this category. */
dataPoints: string[];
/** Whether this category is currently selected by the user. */
selected: boolean;
}
export declare interface DCPMIClassification {
/** Registration tier (or `'none'` when not a DCPMI). */
tier: DCPMITier;
/** Whether the organisation is a Data Controller/Processor of Major Importance. */
isDCPMI: boolean;
/** Annual registration fee in Nigerian Naira (0 when not a volume-tiered DCPMI). */
annualFeeNGN: number;
registration: {
/** Whether NDPC registration is required. */
required: boolean;
/** OHL renews registration annually; UHL/EHL register once and file CAR annually. */
renewsAnnually: boolean;
};
compliance: {
/** Whether the organisation must file annual Compliance Audit Returns (CAR). */
auditReturnsAnnual: boolean;
/** Initial compliance audit is due within this many months of commencing processing. */
initialAuditWithinMonths: number;
};
/** Human-readable caveats and next steps. */
notes: string[];
/** The count actually used for classification, after defensive normalisation. */
dataSubjectsConsidered: number;
}
export declare interface DCPMIClassificationOptions {
thresholds?: Partial<DCPMIThresholds>;
fees?: Partial<DCPMIFees>;
}
export declare interface DCPMIFees {
UHL: number;
EHL: number;
OHL: number;
}
export declare interface DCPMIInput {
/** Distinct data subjects whose data was processed in the relevant six-month window. */
dataSubjectsInSixMonths?: number;
/** True if the Commission has separately designated/listed the organisation as a DCPMI. */
isDesignated?: boolean;
}
export declare interface DCPMIThresholds {
/** Lower bound (inclusive) for OHL. */
ohl: number;
/** Lower bound (inclusive) for EHL. */
ehl: number;
/** A count strictly greater than this is UHL. */
uhl: number;
}
/**
* Data Controller/Processor of Major Importance (DCPMI) classification under the
* NDPC General Application and Implementation Directive (GAID) 2025.
*
* Volume-based tiers — data subjects processed within a six-month window:
* - UHL (Ultra High Level): more than 5,000 → ₦250,000 / year
* - EHL (Extra High Level): 1,000 – 5,000 → ₦100,000 / year
* - OHL (Ordinary High Level): 200 – 999 → ₦10,000 / year
* - below 200: not a DCPMI by volume
*
* Boundaries: the 1,000 mark resolves to EHL (so OHL is 200–999); UHL is
* strictly greater than 5,000 (so 5,000 itself is EHL). The NDPC has revised
* classification metrics before and shifts filing deadlines, so thresholds and
* fees are configurable — treat the defaults as the September 2025 GAID
* baseline, not a constant.
*
* `isDesignated` marks an organisation the Commission has otherwise listed as a
* DCPMI; it is then a DCPMI regardless of volume. Below the volume tiers such an
* organisation is reported as `'listed'` with the fee left at 0 and a note to
* confirm the applicable tier/fee with the NDPC.
*
* @see NDPC General Application and Implementation Directive (GAID) 2025
* @see NDPC Guidance Notice on the Registration of Data Controllers and Processors of Major Importance
*/
export declare type DCPMITier = 'UHL' | 'EHL' | 'OHL' | 'listed' | 'none';
/**
* Cookie scanner — audits the cookies actually present in the browser against
* the cookies you have declared, surfacing undeclared cookies that put you out
* of step with your cookie notice (NDPA 2023 S.25-26 / NDPC GAID 2025 on
* specific, informed consent).
*
* Pure and DOM-optional: pass `cookieString` to scan an arbitrary value (a
* `Cookie:` header on the server, a test fixture), or call it in the browser
* and it reads `document.cookie`. Safe to import from a server bundle.
*/
/** A cookie you declare against a consent category. */
export declare interface DeclaredCookie {
/** Exact cookie name, a prefix (with `prefix: true`), or a RegExp matched against the name. */
name: string | RegExp;
/** Consent category this cookie belongs to (e.g. 'necessary', 'analytics', 'marketing'). */
category: string;
/** Who sets the cookie (e.g. 'Google Analytics'). */
provider?: string;
/** What the cookie is used for — surfaced in your cookie policy. */
purpose?: string;
/** Treat a string `name` as a prefix match instead of an exact match. Ignored for RegExp names. */
prefix?: boolean;
}
/** September 2025 GAID baseline annual fees (NGN). */
export declare const DEFAULT_DCPMI_FEES_NGN: DCPMIFees;
/** September 2025 GAID baseline — override via {@link DCPMIClassificationOptions} as the rules evolve. */
export declare const DEFAULT_DCPMI_THRESHOLDS: DCPMIThresholds;
/**
* Default NDPA-compliant privacy policy sections.
* Each section uses {{variable}} placeholders that are resolved at generation time.
*/
export declare const DEFAULT_POLICY_SECTIONS: PolicySection[];
/**
* Default policy variables for NDPA-compliant privacy policies.
* These map to the {{variable}} placeholders used in DEFAULT_POLICY_SECTIONS.
*/
export declare const DEFAULT_POLICY_VARIABLES: PolicyVariable[];
export declare const defaultLocale: Required<{
[K in keyof NDPRLocale]: Required<NonNullable<NDPRLocale[K]>>;
}>;
/**
* Data Protection Impact Assessment types aligned with NDPA 2023 Section 28
* A DPIA is required when processing is likely to result in high risk to data subjects
*/
/**
* Represents a question in the DPIA questionnaire
*/
export declare interface DPIAQuestion {
/** Unique identifier for the question */
id: string;
/** The text of the question */
text: string;
/** Additional guidance for answering the question */
guidance?: string;
/** Type of input required for the answer */
type: 'text' | 'textarea' | 'select' | 'radio' | 'checkbox' | 'scale';
/** Options for select, radio, or checkbox questions */
options?: Array<{
value: string;
label: string;
riskLevel?: 'low' | 'medium' | 'high';
}>;
/** For scale questions, the minimum value */
minValue?: number;
/** For scale questions, the maximum value */
maxValue?: number;
/** For scale questions, labels for the scale points */
scaleLabels?: Record<number, string>;
/** Whether the question is required */
required: boolean;
/** Risk level associated with this question */
riskLevel?: 'low' | 'medium' | 'high';
/** Whether this question triggers additional questions based on the answer */
hasDependentQuestions?: boolean;
/** Conditions that determine when this question should be shown */
showWhen?: Array<{
questionId: string;
operator: 'equals' | 'contains' | 'greaterThan' | 'lessThan';
value: string | number | boolean;
}>;
}
/**
* Represents the result of a completed DPIA
*/
export declare interface DPIAResult {
/** Unique identifier for the DPIA */
id: string;
/** Title of the DPIA */
title: string;
/** Description of the processing activity being assessed */
processingDescription: string;
/** Timestamp when the DPIA was started */
startedAt: number;
/** Timestamp when the DPIA was completed */
completedAt?: number;
/** Person responsible for conducting the DPIA */
assessor: {
name: string;
role: string;
email: string;
};
/** Answers to all questions in the DPIA */
answers: Record<string, string | number | boolean | string[]>;
/** Risks identified in the DPIA */
risks: DPIARisk[];
/** Overall risk level of the processing activity */
overallRiskLevel: 'low' | 'medium' | 'high' | 'critical';
/** Whether the DPIA concluded that the processing can proceed */
canProceed: boolean;
/** Reasons why the processing can or cannot proceed */
conclusion: string;
/** Recommendations for the processing activity */
recommendations?: string[];
/** Next review date for the DPIA */
reviewDate?: number;
/** Version of the DPIA questionnaire used */
version: string;
/**
* Whether prior consultation with NDPC is required
* Per NDPA Section 28(2), consultation is required when DPIA indicates high residual risk
*/
ndpcConsultationRequired?: boolean;
/** Date when NDPC consultation was initiated */
ndpcConsultationDate?: number;
/** Reference number from NDPC consultation */
ndpcConsultationReference?: string;
/**
* The lawful basis for the processing activity being assessed
*/
lawfulBasis?: string;
/**
* Whether this DPIA involves cross-border data transfers
*/
involvesCrossBorderTransfer?: boolean;
}
/**
* Represents a risk identified in the DPIA
*/
export declare interface DPIARisk {
/** Unique identifier for the risk */
id: string;
/** Description of the risk */
description: string;
/** Likelihood of the risk occurring (1-5) */
likelihood: number;
/** Impact if the risk occurs (1-5) */
impact: number;
/** Overall risk score (likelihood * impact) */
score: number;
/** Risk level based on the score */
level: 'low' | 'medium' | 'high' | 'critical';
/** Measures to mitigate the risk */
mitigationMeasures?: string[];
/** Whether the risk has been mitigated */
mitigated: boolean;
/** Residual risk score after mitigation */
residualScore?: number;
/** Questions that identified this risk */
relatedQuestionIds: string[];
}
/**
* Represents a section in the DPIA questionnaire
*/
export declare interface DPIASection {
/** Unique identifier for the section */
id: string;
/** Title of the section */
title: string;
/** Description of the section */
description?: string;
/** Questions in this section */
questions: DPIAQuestion[];
/** Order of the section in the questionnaire */
order: number;
}
/**
* Represents a data subject request
*/
export declare interface DSRRequest {
/** Unique identifier for the request */
id: string;
/** Type of request */
type: DSRType;
/** Current status of the request */
status: DSRStatus;
/** Timestamp when the request was submitted */
createdAt: number;
/** Timestamp when the request was last updated */
updatedAt: number;
/** Timestamp when the request was completed (if applicable) */
completedAt?: number;
/** Timestamp when the identity was verified (if applicable) */
verifiedAt?: number;
/**
* Due date for responding to the request (timestamp)
* NDPA requires response within 30 days of receipt
*/
dueDate?: number;
/** Description or details of the request */
description?: string;
/**
* The lawful basis under which the data was originally processed
* Relevant for evaluating objection and erasure requests
*/
lawfulBasis?: string;
/** Data subject information */
subject: {
name: string;
email: string;
phone?: string;
identifierValue?: string;
identifierType?: string;
};
/** Additional information provided by the data subject */
additionalInfo?: Record<string, string | number | boolean | null>;
/** Notes added by staff processing the request */
internalNotes?: Array<{
timestamp: number;
author: string;
note: string;
}>;
/** Verification status */
verification?: {
verified: boolean;
method?: string;
verifiedAt?: number;
verifiedBy?: string;
};
/** Reason for rejection (if status is 'rejected') */
rejectionReason?: string;
/** Files attached to the request */
attachments?: Array<{
id: string;
name: string;
type: string;
url: string;
addedAt: number;
}>;
/**
* Whether an extension was requested for this DSR
* NDPA allows a one-time extension of 30 days with justification
*/
extensionRequested?: boolean;
/** Reason for the extension, if requested */
extensionReason?: string;
}
/**
* Status of a data subject request
*/
export declare type DSRStatus = 'pending' | 'awaitingVerification' | 'inProgress' | 'completed' | 'rejected';
/**
* Validated DSR submission shape — matches what `<DSRRequestForm onSubmit>`
* emits client-side. Use this as the typed parameter for your server-side
* handler after `validateDsrSubmissionStructured` returns `valid: true`.
*/
export declare interface DsrSubmissionPayload {
requestType: string;
dataSubject: {
fullName: string;
email: string;
phone?: string;
identifierType: string;
identifierValue: string;
};
additionalInfo?: Record<string, string | number | boolean | null>;
submittedAt: number;
}
/**
* Data Subject Rights types aligned with NDPA 2023 Part VI (Sections 34-38)
* and the related provisions in Part V (Section 27 — information to the data subject)
* and Part X (Section 46 — complaint to the Commission).
*
* Note: These are guidance labels — not legal advice. Verify with your DPO or counsel.
*/
/**
* Types of data subject requests per NDPA Part VI
* - 'information': Right to be informed (Section 27 — provision of information; Section 34(1)(a))
* - 'access': Right of access / confirmation + data copy (Section 34(1)(a)–(b))
* - 'rectification': Right to rectification (Section 34(1)(c))
* - 'erasure': Right to erasure (Section 34(1)(d), Section 34(2))
* - 'restriction': Right to restrict processing (Section 34(1)(e))
* - 'portability': Right to data portability (Section 38)
* - 'objection': Right to object (Section 36)
* - 'automated_decision_making': Rights re. automated decisions / profiling (Section 37)
* - 'withdraw_consent': Right to withdraw consent (Section 35)
*/
export declare type DSRType = 'information' | 'access' | 'rectification' | 'erasure' | 'restriction' | 'portability' | 'objection' | 'automated_decision_making' | 'withdraw_consent';
export declare type EffortLevel = 'low' | 'medium' | 'high';
/**
* NDPA policy compliance checker.
*
* Evaluates a {@link PrivacyPolicy} against 15 requirements drawn from
* the Nigeria Data Protection Act (NDPA) 2023, producing a scored
* {@link ComplianceResult} with actionable gaps.
*
* Scoring:
* 6 critical @ 10 pts = 60
* 5 important @ 7 pts = 35
* 4 recommended @ 5 pts = 20
* Total max = 115
*
* Rating thresholds:
* >= 100 → compliant
* >= 80 → nearly_compliant
* < 80 → not_compliant
*/
/**
* Evaluates a privacy policy against 15 NDPA 2023 requirements and
* returns a scored compliance result with actionable gap information.
*
* @param policy - The privacy policy to evaluate.
* @param context - The template context that was used to generate the policy.
* @returns A {@link ComplianceResult} with score, rating, gaps, and passed ids.
*/
export declare function evaluatePolicyCompliance(policy: PrivacyPolicy, context: TemplateContext): ComplianceResult;
/**
* Exports the Record of Processing Activities to a CSV string.
* The CSV includes all key fields from each processing record.
*
* @param ropa - The full Record of Processing Activities
* @returns CSV-formatted string
*/
export declare function exportROPAToCSV(ropa: RecordOfProcessingActivities): string;
/**
* Scan rendered policy text for unfilled placeholder tokens.
*
* Detects two token forms:
* - `«TODO: fieldName»` — sentinel emitted by {@link assemblePolicy} when
* a required org-info field is missing from the context.
* - `{{fieldName}}` — mustache token that escaped substitution (either
* because the variable wasn't declared or its value was empty).
*
* Returns a deduplicated list of the field names found. An empty array
* means the rendered text is fully populated.
*
* Two recommended uses:
*
* 1. **CI guard** — assert your canonical org-info fixture renders without
* leaving any tokens behind:
* ```ts
* const html = exportHTML(policy);
* expect(findUnfilledTokens(html)).toEqual([]);
* ```
*
* 2. **Runtime guard** — surface a clear error to compliance officers
* before they publish a policy with `{{orgName}}` visible to visitors:
* ```ts
* const missing = findUnfilledTokens(getPolicyText().fullText);
* if (missing.length) throw new Error(`Policy is missing: ${missing.join(', ')}`);
* ```
*
* @param rendered - The substituted policy text (from `exportHTML`,
* `exportMarkdown`, or `usePrivacyPolicy().getPolicyText().fullText`).
* @returns Deduplicated array of unfilled field names; `[]` if fully filled.
*/
export declare function findUnfilledTokens(rendered: string): string[];
export declare interface FormatAuditReportOptions {
/** Wrap status symbols in ANSI colour codes. Default false. */
color?: boolean;
}
/**
* Format a DSR request for display or submission. Returns the formatted
* payload plus a typed `errors` array of `{ field, code, message }` for any
* required fields missing from the source request.
*
* Codes emitted:
* - `request_id_required`
* - `request_type_required`
* - `request_status_required`
* - `created_at_required`
* - `subject_name_required`
* - `subject_email_required`
*/
export declare function formatDSRRequestStructured(request: DSRRequest): FormatDSRRequestStructuredResult;
/** Result of {@link formatDSRRequestStructured}. */
export declare interface FormatDSRRequestStructuredResult {
valid: boolean;
errors: StructuredValidationError[];
/** Formatted request payload — always populated regardless of `valid`. */
formattedRequest: Record<string, unknown>;
/** Narrowed input — populated only on `valid: true`. */
data?: DSRRequest;
}
/**
* Render an `NdprAuditResult` as a plain-text report.
*/
export declare function formatNdprAuditReport(result: NdprAuditResult, options?: FormatAuditReportOptions): string;
export declare const frenchLocale: Required<{
[K in keyof NDPRLocale]: Required<NonNullable<NDPRLocale[K]>>;
}>;
/**
* Derive the CAR schedule and status for a DCPMI under NDPC GAID 2025.
*/
export declare function generateComplianceAuditReturn(input: CARInput, options?: CAROptions): ComplianceAuditReturn;
/**
* Generates a summary of all lawful basis documentation across processing activities.
*
* @param activities Array of processing activities to summarize
* @returns LawfulBasisSummary with counts, breakdowns, and flagged activities
*/
export declare function generateLawfulBasisSummary(activities: ProcessingActivity[]): LawfulBasisSummary;
/**
* Generates policy text by replacing variables in a template with organization-specific values
* @param sectionsOrTemplate The policy sections or template string to generate text for
* @param organizationInfoOrVariables The organization information or variable map to use for replacement
* @returns The generated policy text or an object with the generated text and metadata
*/
export declare function generatePolicyText(sectionsOrTemplate: PolicySection[] | string, organizationInfoOrVariables: OrganizationInfo | Record<string, string>): string | {
fullText: string;
sectionTexts: Record<string, string>;
missingVariables: string[];
};
/**
* Generates a summary of the Record of Processing Activities.
* Provides statistics and identifies records that are due for review.
*
* @param ropa - The full Record of Processing Activities
* @returns Summary statistics for the ROPA
*/
export declare function generateROPASummary(ropa: RecordOfProcessingActivities): ROPASummary;
/**
* Retrieves the full consent audit log from localStorage.
* Returns an empty array if no log exists or parsing fails.
*
* @param storageKey