UNPKG

@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
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