@tantainnovative/ndpr-toolkit 5.2.0 → 5.3.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/CHANGELOG.md +12 -0
- package/README.md +28 -0
- package/dist/chunk-GYLUTVKB.js +1 -0
- package/dist/chunk-KOHFQIV4.mjs +1 -0
- package/dist/chunk-NKFTLFPD.mjs +1 -0
- package/dist/chunk-OXFULQTE.js +1 -0
- package/dist/core.d.mts +93 -0
- package/dist/core.d.ts +93 -0
- package/dist/core.js +1 -1
- package/dist/core.mjs +1 -1
- package/dist/headless.d.mts +364 -5
- package/dist/headless.d.ts +364 -5
- package/dist/headless.js +1 -1
- package/dist/headless.mjs +1 -1
- package/dist/hooks.d.mts +95 -0
- package/dist/hooks.d.ts +95 -0
- package/dist/hooks.js +1 -1
- package/dist/hooks.mjs +1 -1
- package/dist/index.d.mts +101 -0
- package/dist/index.d.ts +101 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/chunk-SDYLKJGC.js +0 -1
- package/dist/chunk-SZXHNJGG.mjs +0 -1
- package/dist/chunk-TQCKLZ4F.mjs +0 -1
- package/dist/chunk-WKY26JLT.js +0 -1
- /package/dist/{chunk-MR7YZZDU.js → chunk-OVW5ASY3.js} +0 -0
- /package/dist/{chunk-65TYKXUI.mjs → chunk-YQTZWPOS.mjs} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [5.3.0](https://github.com/mr-tanta/ndpr-toolkit/compare/v5.2.0...v5.3.0) (2026-05-30)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **breach:** add NDPA S.40 / GAID 2025 Article 33 notification completeness checker ([2a6bdf2](https://github.com/mr-tanta/ndpr-toolkit/commit/2a6bdf25af11431c6b4603c0892d3db44f0bf348))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Documentation
|
|
14
|
+
|
|
15
|
+
* document the breach notification completeness checker ([c05ee84](https://github.com/mr-tanta/ndpr-toolkit/commit/c05ee848afd899ae916b40fa55023886380392ae))
|
|
16
|
+
|
|
5
17
|
## [5.2.0](https://github.com/mr-tanta/ndpr-toolkit/compare/v5.1.4...v5.2.0) (2026-05-30)
|
|
6
18
|
|
|
7
19
|
|
package/README.md
CHANGED
|
@@ -506,6 +506,34 @@ Both ship as memoised hooks for React UIs — `useDCPMI(input, options?)` and `u
|
|
|
506
506
|
|
|
507
507
|
---
|
|
508
508
|
|
|
509
|
+
## Breach Notification Completeness
|
|
510
|
+
|
|
511
|
+
`assessBreachNotification()` checks a `BreachReport` against the **NDPA 2023 Section 40** breach-notification duty as detailed by **NDPC GAID 2025 Article 33** — the mandated content of the notification to the Commission, the 72-hour deadline from discovery, and the data-subject communication owed when the risk is high.
|
|
512
|
+
|
|
513
|
+
```ts
|
|
514
|
+
import { assessBreachNotification } from '@tantainnovative/ndpr-toolkit/core';
|
|
515
|
+
|
|
516
|
+
const result = assessBreachNotification(breachReport, {
|
|
517
|
+
asOf: Date.now(),
|
|
518
|
+
assessment: riskAssessment, // optional — high risk triggers the S.40(3) data-subject duty
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
result.complete; // false until every mandated item is present
|
|
522
|
+
result.completeness; // 0–100 across applicable items
|
|
523
|
+
result.missing; // ["Steps taken to reduce the risk of harm", ...]
|
|
524
|
+
result.timing.deadline; // discoveredAt + 72h
|
|
525
|
+
result.timing.hoursRemaining;// time left to notify the NDPC (negative once overdue)
|
|
526
|
+
result.timing.overdue; // true once the 72-hour window has passed
|
|
527
|
+
result.dataSubjectCommunicationRequired; // true on high risk (S.40(3))
|
|
528
|
+
result.recommendations; // actionable, each citing its provision
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
The content checklist (`notificationToCommission`) maps each item to its source — **GAID 2025 Art. 33(5)(a)–(h)** for the description, timing, data involved, risk-of-harm, numbers at risk, mitigation, notification steps, and contact point; **NDPA S. 40(2)** for the data-subject categories and record count. Late filings are flagged with `requiresDelayJustification` (the NDPC permits phased reporting where full details aren't yet available). Also available as the memoised `useBreachNotificationAssessment(report, options?)` hook from `/hooks`.
|
|
532
|
+
|
|
533
|
+
> A documentation-completeness aid, not legal advice — verify against current NDPC guidance.
|
|
534
|
+
|
|
535
|
+
---
|
|
536
|
+
|
|
509
537
|
## Backend Integration
|
|
510
538
|
|
|
511
539
|
### CLI scaffolder
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use strict';var chunkOXFULQTE_js=require('./chunk-OXFULQTE.js'),chunk7TTXS7JX_js=require('./chunk-7TTXS7JX.js'),react=require('react');function u(t,e){return react.useMemo(()=>chunkOXFULQTE_js.a(t,e),[t,e])}function M({input:t}){let e=JSON.stringify(t);return react.useMemo(()=>chunk7TTXS7JX_js.a(t),[e])}function D(t,e){return react.useMemo(()=>chunkOXFULQTE_js.d(t,e),[t.dataSubjectsInSixMonths,t.isDesignated,e])}function P(t,e){return react.useMemo(()=>chunkOXFULQTE_js.e(t,e),[t.commencementDate,t.asOf,t.tier,e])}exports.a=u;exports.b=M;exports.c=D;exports.d=P;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {a}from'./chunk-ZJYULEER.mjs';var d=e=>typeof e=="string"&&e.trim().length>0,R=e=>typeof e=="number"&&Number.isFinite(e)&&e>=0,x=e=>Array.isArray(e)&&e.length>0,H=e=>!!e&&d(e.name)&&d(e.email);function G(e,n={}){var C,A,I,N,O;let i=(C=n.asOf)!=null?C:Date.now(),r=(A=n.deadlineHours)!=null?A:72,s=e.discoveredAt+r*36e5,o=n.notification,t=!!o,c=o==null?void 0:o.sentAt,a=(t?c:i)>s,h={deadline:s,hoursSinceDiscovery:Math.round((i-e.discoveredAt)/36e5),notified:t,notifiedAt:c,withinDeadline:!a,hoursRemaining:Math.round((s-i)/36e5),overdue:a,requiresDelayJustification:a},f=[{id:"circumstances",label:"Description of the circumstances of the breach",section:"GAID 2025 Art. 33(5)(a)",satisfied:d(e.description)},{id:"occurrence",label:"Date or time period of the breach",section:"GAID 2025 Art. 33(5)(b)",satisfied:R(e.occurredAt)},{id:"personalInfo",label:"Description of the personal data involved",section:"GAID 2025 Art. 33(5)(c)",satisfied:x(e.dataTypes)},{id:"riskOfHarm",label:"Assessment of the risk of harm to data subjects",section:"GAID 2025 Art. 33(5)(d)",satisfied:d(e.likelyConsequences)},{id:"numberAtRisk",label:"Estimated number of data subjects at risk of significant harm",section:"GAID 2025 Art. 33(5)(e)",satisfied:R(e.estimatedAffectedSubjects)},{id:"mitigation",label:"Steps taken to reduce the risk of harm",section:"GAID 2025 Art. 33(5)(f)",satisfied:d(e.mitigationMeasures)},{id:"notifySteps",label:"Steps taken to notify affected data subjects",section:"GAID 2025 Art. 33(5)(g)",satisfied:d(e.initialActions)},{id:"contactPoint",label:"Name and contact details of a contact point",section:"GAID 2025 Art. 33(5)(h)",satisfied:H(e.dpoContact)},{id:"dataSubjectCategories",label:"Categories of data subjects concerned",section:"NDPA 2023 S. 40(2)",satisfied:x(e.dataSubjectCategories)},{id:"recordCount",label:"Approximate number of personal data records concerned",section:"NDPA 2023 S. 40(2)",satisfied:R(e.approximateRecordCount)}],D=(O=(N=n.highRisk)!=null?N:(I=n.assessment)==null?void 0:I.highRisksToRightsAndFreedoms)!=null?O:false,g=D?[{id:"dsNature",label:"Nature and context of the breach in plain language",section:"NDPA 2023 S. 40(3)",satisfied:d(e.description)},{id:"dsConsequences",label:"Likely consequences of the breach",section:"NDPA 2023 S. 40(3)",satisfied:d(e.likelyConsequences)},{id:"dsMeasures",label:"Safeguards and measures data subjects can take",section:"NDPA 2023 S. 40(3)",satisfied:d(e.mitigationMeasures)},{id:"dsContact",label:"Contact point for data subjects",section:"NDPA 2023 S. 40(3)",satisfied:H(e.dpoContact)}]:[],l=[...f,...g],P=l.filter(m=>m.satisfied).length,S=Math.round(P/l.length*100),p=l.filter(m=>!m.satisfied).map(m=>m.label),y=p.length===0,u=[];for(let m of l.filter(L=>!L.satisfied))u.push(`Add: ${m.label} (${m.section}).`);return a?u.push("The 72-hour notification deadline has passed \u2014 notify the NDPC now and state the reasons for the delay; phased reporting is permitted where complete details are not yet available (NDPA S. 40(2))."):t||u.push(`${Math.max(0,h.hoursRemaining)} hour(s) remain to notify the NDPC within the 72-hour window (NDPA S. 40(2)).`),D&&u.push("High risk to data subjects \u2014 communicate the breach to affected data subjects immediately, in plain and clear language (NDPA S. 40(3))."),{complete:y,completeness:S,notificationToCommission:f,dataSubjectCommunication:g,dataSubjectCommunicationRequired:D,timing:h,missing:p,recommendations:u,asOf:i}}var j={ohl:200,ehl:1e3,uhl:5e3},k={UHL:25e4,EHL:1e5,OHL:1e4};function _(e,n={}){let i=a(a({},j),n.thresholds),r=a(a({},k),n.fees),s=e==null?void 0:e.dataSubjectsInSixMonths,o=typeof s=="number"&&s>0?Math.floor(s):0,t;o>i.uhl?t="UHL":o>=i.ehl?t="EHL":o>=i.ohl?t="OHL":e!=null&&e.isDesignated?t="listed":t="none";let c=t!=="none",b=t==="UHL"||t==="EHL"||t==="OHL"?r[t]:0,a$1=[];return t==="listed"&&a$1.push("Designated as a DCPMI below the volume tiers \u2014 confirm the applicable registration tier and fee with the NDPC."),c&&a$1.push(t==="OHL"?"OHL organisations renew their NDPC registration annually and file Compliance Audit Returns (CAR) each year.":"Register once with the NDPC, then file Compliance Audit Returns (CAR) annually."),a$1.push("Thresholds, fees, and filing dates follow the NDPC GAID 2025 baseline and can change \u2014 verify against current NDPC guidance before relying on them."),{tier:t,isDCPMI:c,annualFeeNGN:b,registration:{required:c,renewsAnnually:t==="OHL"},compliance:{auditReturnsAnnual:c,initialAuditWithinMonths:15},notes:a$1,dataSubjectsConsidered:o}}function w(e){return String(e).padStart(2,"0")}function T(e){let[n,i,r]=e.split("-").map(Number);return new Date(Date.UTC(n,i-1,r))}function B(e){return e.toISOString().slice(0,10)}function U(e,n){let[i,r,s]=e.split("-").map(Number);return B(new Date(Date.UTC(i,r-1+n,s)))}function F(){return new Date().toISOString().slice(0,10)}function W(e,n={}){var P,S,p,y,u,C,A;let i=(P=e.asOf)!=null?P:F(),r=(S=n.initialAuditWithinMonths)!=null?S:15,s=(y=(p=n.annualDeadline)==null?void 0:p.month)!=null?y:3,o=(C=(u=n.annualDeadline)==null?void 0:u.day)!=null?C:31,t=(A=n.deadlineOverrides)!=null?A:{},c=e.tier===void 0?true:e.tier!=="none",b=U(e.commencementDate,r),a=I=>{var N;return (N=t[I])!=null?N:`${I}-${w(s)}-${w(o)}`},h=Number(i.slice(0,4)),f=a(h);i>f&&(h+=1,f=a(h));let D=Math.round((T(f).getTime()-T(i).getTime())/864e5),g=i>=b,l=[];return c?(l.push("File the Compliance Audit Return with the NDPC via the NDPC Information Management Portal (NIMP)."),g&&l.push("The initial compliance-audit window has elapsed \u2014 ensure the initial audit has been conducted.")):l.push("Compliance Audit Returns apply only to Data Controllers/Processors of Major Importance."),l.push("Filing deadlines follow the NDPC GAID 2025 baseline and can be extended \u2014 verify the current deadline with the NDPC."),{applicable:c,schedule:{commencementDate:e.commencementDate,initialAuditWithinMonths:r,initialAuditDueDate:b,nextFilingDeadline:f,filingYear:h},status:{initialAuditDue:g,daysUntilNextDeadline:D},notes:l,asOf:i}}export{G as a,j as b,k as c,_ as d,W as e};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {a,d,e}from'./chunk-KOHFQIV4.mjs';import {a as a$1}from'./chunk-6A7M4CGJ.mjs';import {useMemo}from'react';function u(t,e){return useMemo(()=>a(t,e),[t,e])}function M({input:t}){let e=JSON.stringify(t);return useMemo(()=>a$1(t),[e])}function D(t,e){return useMemo(()=>d(t,e),[t.dataSubjectsInSixMonths,t.isDesignated,e])}function P(t,e$1){return useMemo(()=>e(t,e$1),[t.commencementDate,t.asOf,t.tier,e$1])}export{u as a,M as b,D as c,P as d};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use strict';var chunkRFPLZDIO_js=require('./chunk-RFPLZDIO.js');var d=e=>typeof e=="string"&&e.trim().length>0,R=e=>typeof e=="number"&&Number.isFinite(e)&&e>=0,x=e=>Array.isArray(e)&&e.length>0,H=e=>!!e&&d(e.name)&&d(e.email);function G(e,n={}){var C,A,I,N,O;let i=(C=n.asOf)!=null?C:Date.now(),r=(A=n.deadlineHours)!=null?A:72,s=e.discoveredAt+r*36e5,o=n.notification,t=!!o,c=o==null?void 0:o.sentAt,a=(t?c:i)>s,h={deadline:s,hoursSinceDiscovery:Math.round((i-e.discoveredAt)/36e5),notified:t,notifiedAt:c,withinDeadline:!a,hoursRemaining:Math.round((s-i)/36e5),overdue:a,requiresDelayJustification:a},f=[{id:"circumstances",label:"Description of the circumstances of the breach",section:"GAID 2025 Art. 33(5)(a)",satisfied:d(e.description)},{id:"occurrence",label:"Date or time period of the breach",section:"GAID 2025 Art. 33(5)(b)",satisfied:R(e.occurredAt)},{id:"personalInfo",label:"Description of the personal data involved",section:"GAID 2025 Art. 33(5)(c)",satisfied:x(e.dataTypes)},{id:"riskOfHarm",label:"Assessment of the risk of harm to data subjects",section:"GAID 2025 Art. 33(5)(d)",satisfied:d(e.likelyConsequences)},{id:"numberAtRisk",label:"Estimated number of data subjects at risk of significant harm",section:"GAID 2025 Art. 33(5)(e)",satisfied:R(e.estimatedAffectedSubjects)},{id:"mitigation",label:"Steps taken to reduce the risk of harm",section:"GAID 2025 Art. 33(5)(f)",satisfied:d(e.mitigationMeasures)},{id:"notifySteps",label:"Steps taken to notify affected data subjects",section:"GAID 2025 Art. 33(5)(g)",satisfied:d(e.initialActions)},{id:"contactPoint",label:"Name and contact details of a contact point",section:"GAID 2025 Art. 33(5)(h)",satisfied:H(e.dpoContact)},{id:"dataSubjectCategories",label:"Categories of data subjects concerned",section:"NDPA 2023 S. 40(2)",satisfied:x(e.dataSubjectCategories)},{id:"recordCount",label:"Approximate number of personal data records concerned",section:"NDPA 2023 S. 40(2)",satisfied:R(e.approximateRecordCount)}],D=(O=(N=n.highRisk)!=null?N:(I=n.assessment)==null?void 0:I.highRisksToRightsAndFreedoms)!=null?O:false,g=D?[{id:"dsNature",label:"Nature and context of the breach in plain language",section:"NDPA 2023 S. 40(3)",satisfied:d(e.description)},{id:"dsConsequences",label:"Likely consequences of the breach",section:"NDPA 2023 S. 40(3)",satisfied:d(e.likelyConsequences)},{id:"dsMeasures",label:"Safeguards and measures data subjects can take",section:"NDPA 2023 S. 40(3)",satisfied:d(e.mitigationMeasures)},{id:"dsContact",label:"Contact point for data subjects",section:"NDPA 2023 S. 40(3)",satisfied:H(e.dpoContact)}]:[],l=[...f,...g],P=l.filter(m=>m.satisfied).length,S=Math.round(P/l.length*100),p=l.filter(m=>!m.satisfied).map(m=>m.label),y=p.length===0,u=[];for(let m of l.filter(L=>!L.satisfied))u.push(`Add: ${m.label} (${m.section}).`);return a?u.push("The 72-hour notification deadline has passed \u2014 notify the NDPC now and state the reasons for the delay; phased reporting is permitted where complete details are not yet available (NDPA S. 40(2))."):t||u.push(`${Math.max(0,h.hoursRemaining)} hour(s) remain to notify the NDPC within the 72-hour window (NDPA S. 40(2)).`),D&&u.push("High risk to data subjects \u2014 communicate the breach to affected data subjects immediately, in plain and clear language (NDPA S. 40(3))."),{complete:y,completeness:S,notificationToCommission:f,dataSubjectCommunication:g,dataSubjectCommunicationRequired:D,timing:h,missing:p,recommendations:u,asOf:i}}var j={ohl:200,ehl:1e3,uhl:5e3},k={UHL:25e4,EHL:1e5,OHL:1e4};function _(e,n={}){let i=chunkRFPLZDIO_js.a(chunkRFPLZDIO_js.a({},j),n.thresholds),r=chunkRFPLZDIO_js.a(chunkRFPLZDIO_js.a({},k),n.fees),s=e==null?void 0:e.dataSubjectsInSixMonths,o=typeof s=="number"&&s>0?Math.floor(s):0,t;o>i.uhl?t="UHL":o>=i.ehl?t="EHL":o>=i.ohl?t="OHL":e!=null&&e.isDesignated?t="listed":t="none";let c=t!=="none",b=t==="UHL"||t==="EHL"||t==="OHL"?r[t]:0,a=[];return t==="listed"&&a.push("Designated as a DCPMI below the volume tiers \u2014 confirm the applicable registration tier and fee with the NDPC."),c&&a.push(t==="OHL"?"OHL organisations renew their NDPC registration annually and file Compliance Audit Returns (CAR) each year.":"Register once with the NDPC, then file Compliance Audit Returns (CAR) annually."),a.push("Thresholds, fees, and filing dates follow the NDPC GAID 2025 baseline and can change \u2014 verify against current NDPC guidance before relying on them."),{tier:t,isDCPMI:c,annualFeeNGN:b,registration:{required:c,renewsAnnually:t==="OHL"},compliance:{auditReturnsAnnual:c,initialAuditWithinMonths:15},notes:a,dataSubjectsConsidered:o}}function w(e){return String(e).padStart(2,"0")}function T(e){let[n,i,r]=e.split("-").map(Number);return new Date(Date.UTC(n,i-1,r))}function B(e){return e.toISOString().slice(0,10)}function U(e,n){let[i,r,s]=e.split("-").map(Number);return B(new Date(Date.UTC(i,r-1+n,s)))}function F(){return new Date().toISOString().slice(0,10)}function W(e,n={}){var P,S,p,y,u,C,A;let i=(P=e.asOf)!=null?P:F(),r=(S=n.initialAuditWithinMonths)!=null?S:15,s=(y=(p=n.annualDeadline)==null?void 0:p.month)!=null?y:3,o=(C=(u=n.annualDeadline)==null?void 0:u.day)!=null?C:31,t=(A=n.deadlineOverrides)!=null?A:{},c=e.tier===void 0?true:e.tier!=="none",b=U(e.commencementDate,r),a=I=>{var N;return (N=t[I])!=null?N:`${I}-${w(s)}-${w(o)}`},h=Number(i.slice(0,4)),f=a(h);i>f&&(h+=1,f=a(h));let D=Math.round((T(f).getTime()-T(i).getTime())/864e5),g=i>=b,l=[];return c?(l.push("File the Compliance Audit Return with the NDPC via the NDPC Information Management Portal (NIMP)."),g&&l.push("The initial compliance-audit window has elapsed \u2014 ensure the initial audit has been conducted.")):l.push("Compliance Audit Returns apply only to Data Controllers/Processors of Major Importance."),l.push("Filing deadlines follow the NDPC GAID 2025 baseline and can be extended \u2014 verify the current deadline with the NDPC."),{applicable:c,schedule:{commencementDate:e.commencementDate,initialAuditWithinMonths:r,initialAuditDueDate:b,nextFilingDeadline:f,filingYear:h},status:{initialAuditDue:g,daysUntilNextDeadline:D},notes:l,asOf:i}}exports.a=G;exports.b=j;exports.c=k;exports.d=_;exports.e=W;
|
package/dist/core.d.mts
CHANGED
|
@@ -62,6 +62,12 @@ export declare const arabicLocale: Required<{
|
|
|
62
62
|
*/
|
|
63
63
|
export declare function assemblePolicy(context: TemplateContext): PolicySection[];
|
|
64
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Assess a breach report against the NDPA S. 40 / GAID 2025 Article 33
|
|
67
|
+
* notification requirements.
|
|
68
|
+
*/
|
|
69
|
+
export declare function assessBreachNotification(report: BreachReport, options?: BreachNotificationOptions): BreachNotificationAssessment;
|
|
70
|
+
|
|
65
71
|
/**
|
|
66
72
|
* Analyzes all processing activities and returns compliance gaps including
|
|
67
73
|
* missing DPO approval, overdue reviews, undocumented justifications,
|
|
@@ -112,6 +118,93 @@ export declare interface BreachCategory {
|
|
|
112
118
|
defaultSeverity: 'low' | 'medium' | 'high' | 'critical';
|
|
113
119
|
}
|
|
114
120
|
|
|
121
|
+
export declare interface BreachNotificationAssessment {
|
|
122
|
+
/** Whether all applicable mandated content items are satisfied. */
|
|
123
|
+
complete: boolean;
|
|
124
|
+
/** Completeness of applicable content items, 0–100. */
|
|
125
|
+
completeness: number;
|
|
126
|
+
/** GAID 2025 Article 33(5) / NDPA S. 40(2) content of the notification to the Commission. */
|
|
127
|
+
notificationToCommission: BreachNotificationItem[];
|
|
128
|
+
/** NDPA S. 40(3) communication to data subjects — populated only when high-risk. */
|
|
129
|
+
dataSubjectCommunication: BreachNotificationItem[];
|
|
130
|
+
/** Whether a data-subject communication is owed (high risk). */
|
|
131
|
+
dataSubjectCommunicationRequired: boolean;
|
|
132
|
+
timing: BreachNotificationTiming;
|
|
133
|
+
/** Labels of unsatisfied applicable items. */
|
|
134
|
+
missing: string[];
|
|
135
|
+
/** Actionable next steps, including timing warnings. */
|
|
136
|
+
recommendations: string[];
|
|
137
|
+
asOf: number;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export declare interface BreachNotificationItem {
|
|
141
|
+
/** Stable identifier for the requirement. */
|
|
142
|
+
id: string;
|
|
143
|
+
/** Human-readable requirement. */
|
|
144
|
+
label: string;
|
|
145
|
+
/** Authoritative citation, e.g. `GAID 2025 Art. 33(5)(a)`. */
|
|
146
|
+
section: string;
|
|
147
|
+
/** Whether the report satisfies it. */
|
|
148
|
+
satisfied: boolean;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Personal-data-breach notification completeness checker for NDPA 2023
|
|
153
|
+
* Section 40, as detailed by NDPC General Application and Implementation
|
|
154
|
+
* Directive (GAID) 2025 Article 33.
|
|
155
|
+
*
|
|
156
|
+
* Section 40(2) requires a data controller to notify the Commission within 72
|
|
157
|
+
* hours of becoming aware of a breach likely to result in a risk to data
|
|
158
|
+
* subjects' rights and freedoms. GAID 2025 Article 33(5)(a)–(h) enumerates the
|
|
159
|
+
* content that a notification to the Commission "shall include". Where the
|
|
160
|
+
* breach is likely to result in a *high* risk, Section 40(3) additionally
|
|
161
|
+
* requires the controller to communicate the breach to affected data subjects
|
|
162
|
+
* in plain and clear language.
|
|
163
|
+
*
|
|
164
|
+
* This assesses a `BreachReport` against those requirements: which mandated
|
|
165
|
+
* content items are present, whether the 72-hour window is met, and whether a
|
|
166
|
+
* data-subject communication is owed. It is a documentation-completeness aid,
|
|
167
|
+
* not legal advice — verify against current NDPC guidance.
|
|
168
|
+
*
|
|
169
|
+
* @see NDPA 2023 Section 40 (Personal data breaches)
|
|
170
|
+
* @see NDPC GAID 2025 Article 33 (Data Breach Notification)
|
|
171
|
+
*/
|
|
172
|
+
|
|
173
|
+
export declare interface BreachNotificationOptions {
|
|
174
|
+
/** Risk assessment for the breach; drives whether data-subject communication is required. */
|
|
175
|
+
assessment?: RiskAssessment;
|
|
176
|
+
/** The regulatory notification actually sent, if any — used to judge timeliness. */
|
|
177
|
+
notification?: RegulatoryNotification;
|
|
178
|
+
/** Reference "now" in epoch ms. Defaults to `Date.now()`. */
|
|
179
|
+
asOf?: number;
|
|
180
|
+
/** Notification window in hours. Defaults to 72 (NDPA S. 40(2)). */
|
|
181
|
+
deadlineHours?: number;
|
|
182
|
+
/**
|
|
183
|
+
* Explicit high-risk flag (NDPA S. 40(3)). When omitted, derived from
|
|
184
|
+
* `assessment.highRisksToRightsAndFreedoms`.
|
|
185
|
+
*/
|
|
186
|
+
highRisk?: boolean;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export declare interface BreachNotificationTiming {
|
|
190
|
+
/** `discoveredAt` + the notification window. */
|
|
191
|
+
deadline: number;
|
|
192
|
+
/** Whole hours between discovery and `asOf`. */
|
|
193
|
+
hoursSinceDiscovery: number;
|
|
194
|
+
/** Whether a regulatory notification has been recorded. */
|
|
195
|
+
notified: boolean;
|
|
196
|
+
/** When the regulatory notification was sent, if any. */
|
|
197
|
+
notifiedAt?: number;
|
|
198
|
+
/** Whether the notification (or, if none, `asOf`) falls within the deadline. */
|
|
199
|
+
withinDeadline: boolean;
|
|
200
|
+
/** Whole hours from `asOf` to the deadline (negative once past). */
|
|
201
|
+
hoursRemaining: number;
|
|
202
|
+
/** Whether the deadline has been missed. */
|
|
203
|
+
overdue: boolean;
|
|
204
|
+
/** Late filings must state the reasons for the delay (NDPA S. 40(2)). */
|
|
205
|
+
requiresDelayJustification: boolean;
|
|
206
|
+
}
|
|
207
|
+
|
|
115
208
|
/**
|
|
116
209
|
* Represents a data breach report
|
|
117
210
|
*/
|
package/dist/core.d.ts
CHANGED
|
@@ -62,6 +62,12 @@ export declare const arabicLocale: Required<{
|
|
|
62
62
|
*/
|
|
63
63
|
export declare function assemblePolicy(context: TemplateContext): PolicySection[];
|
|
64
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Assess a breach report against the NDPA S. 40 / GAID 2025 Article 33
|
|
67
|
+
* notification requirements.
|
|
68
|
+
*/
|
|
69
|
+
export declare function assessBreachNotification(report: BreachReport, options?: BreachNotificationOptions): BreachNotificationAssessment;
|
|
70
|
+
|
|
65
71
|
/**
|
|
66
72
|
* Analyzes all processing activities and returns compliance gaps including
|
|
67
73
|
* missing DPO approval, overdue reviews, undocumented justifications,
|
|
@@ -112,6 +118,93 @@ export declare interface BreachCategory {
|
|
|
112
118
|
defaultSeverity: 'low' | 'medium' | 'high' | 'critical';
|
|
113
119
|
}
|
|
114
120
|
|
|
121
|
+
export declare interface BreachNotificationAssessment {
|
|
122
|
+
/** Whether all applicable mandated content items are satisfied. */
|
|
123
|
+
complete: boolean;
|
|
124
|
+
/** Completeness of applicable content items, 0–100. */
|
|
125
|
+
completeness: number;
|
|
126
|
+
/** GAID 2025 Article 33(5) / NDPA S. 40(2) content of the notification to the Commission. */
|
|
127
|
+
notificationToCommission: BreachNotificationItem[];
|
|
128
|
+
/** NDPA S. 40(3) communication to data subjects — populated only when high-risk. */
|
|
129
|
+
dataSubjectCommunication: BreachNotificationItem[];
|
|
130
|
+
/** Whether a data-subject communication is owed (high risk). */
|
|
131
|
+
dataSubjectCommunicationRequired: boolean;
|
|
132
|
+
timing: BreachNotificationTiming;
|
|
133
|
+
/** Labels of unsatisfied applicable items. */
|
|
134
|
+
missing: string[];
|
|
135
|
+
/** Actionable next steps, including timing warnings. */
|
|
136
|
+
recommendations: string[];
|
|
137
|
+
asOf: number;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export declare interface BreachNotificationItem {
|
|
141
|
+
/** Stable identifier for the requirement. */
|
|
142
|
+
id: string;
|
|
143
|
+
/** Human-readable requirement. */
|
|
144
|
+
label: string;
|
|
145
|
+
/** Authoritative citation, e.g. `GAID 2025 Art. 33(5)(a)`. */
|
|
146
|
+
section: string;
|
|
147
|
+
/** Whether the report satisfies it. */
|
|
148
|
+
satisfied: boolean;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Personal-data-breach notification completeness checker for NDPA 2023
|
|
153
|
+
* Section 40, as detailed by NDPC General Application and Implementation
|
|
154
|
+
* Directive (GAID) 2025 Article 33.
|
|
155
|
+
*
|
|
156
|
+
* Section 40(2) requires a data controller to notify the Commission within 72
|
|
157
|
+
* hours of becoming aware of a breach likely to result in a risk to data
|
|
158
|
+
* subjects' rights and freedoms. GAID 2025 Article 33(5)(a)–(h) enumerates the
|
|
159
|
+
* content that a notification to the Commission "shall include". Where the
|
|
160
|
+
* breach is likely to result in a *high* risk, Section 40(3) additionally
|
|
161
|
+
* requires the controller to communicate the breach to affected data subjects
|
|
162
|
+
* in plain and clear language.
|
|
163
|
+
*
|
|
164
|
+
* This assesses a `BreachReport` against those requirements: which mandated
|
|
165
|
+
* content items are present, whether the 72-hour window is met, and whether a
|
|
166
|
+
* data-subject communication is owed. It is a documentation-completeness aid,
|
|
167
|
+
* not legal advice — verify against current NDPC guidance.
|
|
168
|
+
*
|
|
169
|
+
* @see NDPA 2023 Section 40 (Personal data breaches)
|
|
170
|
+
* @see NDPC GAID 2025 Article 33 (Data Breach Notification)
|
|
171
|
+
*/
|
|
172
|
+
|
|
173
|
+
export declare interface BreachNotificationOptions {
|
|
174
|
+
/** Risk assessment for the breach; drives whether data-subject communication is required. */
|
|
175
|
+
assessment?: RiskAssessment;
|
|
176
|
+
/** The regulatory notification actually sent, if any — used to judge timeliness. */
|
|
177
|
+
notification?: RegulatoryNotification;
|
|
178
|
+
/** Reference "now" in epoch ms. Defaults to `Date.now()`. */
|
|
179
|
+
asOf?: number;
|
|
180
|
+
/** Notification window in hours. Defaults to 72 (NDPA S. 40(2)). */
|
|
181
|
+
deadlineHours?: number;
|
|
182
|
+
/**
|
|
183
|
+
* Explicit high-risk flag (NDPA S. 40(3)). When omitted, derived from
|
|
184
|
+
* `assessment.highRisksToRightsAndFreedoms`.
|
|
185
|
+
*/
|
|
186
|
+
highRisk?: boolean;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export declare interface BreachNotificationTiming {
|
|
190
|
+
/** `discoveredAt` + the notification window. */
|
|
191
|
+
deadline: number;
|
|
192
|
+
/** Whole hours between discovery and `asOf`. */
|
|
193
|
+
hoursSinceDiscovery: number;
|
|
194
|
+
/** Whether a regulatory notification has been recorded. */
|
|
195
|
+
notified: boolean;
|
|
196
|
+
/** When the regulatory notification was sent, if any. */
|
|
197
|
+
notifiedAt?: number;
|
|
198
|
+
/** Whether the notification (or, if none, `asOf`) falls within the deadline. */
|
|
199
|
+
withinDeadline: boolean;
|
|
200
|
+
/** Whole hours from `asOf` to the deadline (negative once past). */
|
|
201
|
+
hoursRemaining: number;
|
|
202
|
+
/** Whether the deadline has been missed. */
|
|
203
|
+
overdue: boolean;
|
|
204
|
+
/** Late filings must state the reasons for the delay (NDPA S. 40(2)). */
|
|
205
|
+
requiresDelayJustification: boolean;
|
|
206
|
+
}
|
|
207
|
+
|
|
115
208
|
/**
|
|
116
209
|
* Represents a data breach report
|
|
117
210
|
*/
|
package/dist/core.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
'use strict';var chunkLP5KXMBY_js=require('./chunk-LP5KXMBY.js'),chunkNUOHT3LO_js=require('./chunk-NUOHT3LO.js'),
|
|
1
|
+
'use strict';var chunkLP5KXMBY_js=require('./chunk-LP5KXMBY.js'),chunkNUOHT3LO_js=require('./chunk-NUOHT3LO.js'),chunkOXFULQTE_js=require('./chunk-OXFULQTE.js'),chunk7TTXS7JX_js=require('./chunk-7TTXS7JX.js'),chunk3YTAOT5O_js=require('./chunk-3YTAOT5O.js'),chunkD2ZKDQVL_js=require('./chunk-D2ZKDQVL.js'),chunk6LJHLE6G_js=require('./chunk-6LJHLE6G.js'),chunkYFBDJ4FH_js=require('./chunk-YFBDJ4FH.js'),chunkWZYCBW2R_js=require('./chunk-WZYCBW2R.js'),chunk4CVBQC66_js=require('./chunk-4CVBQC66.js'),chunk3IA3KDII_js=require('./chunk-3IA3KDII.js'),chunkDKLJ5DYN_js=require('./chunk-DKLJ5DYN.js'),chunkUXUMYP4L_js=require('./chunk-UXUMYP4L.js'),chunkR2ZZMATR_js=require('./chunk-R2ZZMATR.js'),chunkTQZWJGJ2_js=require('./chunk-TQZWJGJ2.js'),chunkZVOIR4QH_js=require('./chunk-ZVOIR4QH.js'),chunkI5ZDNSX5_js=require('./chunk-I5ZDNSX5.js'),chunk7563FVMY_js=require('./chunk-7563FVMY.js');require('./chunk-RFPLZDIO.js');Object.defineProperty(exports,"arabicLocale",{enumerable:true,get:function(){return chunkLP5KXMBY_js.e}});Object.defineProperty(exports,"frenchLocale",{enumerable:true,get:function(){return chunkLP5KXMBY_js.f}});Object.defineProperty(exports,"hausaLocale",{enumerable:true,get:function(){return chunkLP5KXMBY_js.c}});Object.defineProperty(exports,"igboLocale",{enumerable:true,get:function(){return chunkLP5KXMBY_js.b}});Object.defineProperty(exports,"pidginLocale",{enumerable:true,get:function(){return chunkLP5KXMBY_js.d}});Object.defineProperty(exports,"yorubaLocale",{enumerable:true,get:function(){return chunkLP5KXMBY_js.a}});Object.defineProperty(exports,"ORG_POLICY_TEMPLATE_REGISTRY",{enumerable:true,get:function(){return chunkNUOHT3LO_js.a}});Object.defineProperty(exports,"createOrgTemplate",{enumerable:true,get:function(){return chunkNUOHT3LO_js.b}});Object.defineProperty(exports,"templateContextFor",{enumerable:true,get:function(){return chunkNUOHT3LO_js.b}});Object.defineProperty(exports,"DEFAULT_DCPMI_FEES_NGN",{enumerable:true,get:function(){return chunkOXFULQTE_js.c}});Object.defineProperty(exports,"DEFAULT_DCPMI_THRESHOLDS",{enumerable:true,get:function(){return chunkOXFULQTE_js.b}});Object.defineProperty(exports,"assessBreachNotification",{enumerable:true,get:function(){return chunkOXFULQTE_js.a}});Object.defineProperty(exports,"classifyDCPMI",{enumerable:true,get:function(){return chunkOXFULQTE_js.d}});Object.defineProperty(exports,"generateComplianceAuditReturn",{enumerable:true,get:function(){return chunkOXFULQTE_js.e}});Object.defineProperty(exports,"getComplianceScore",{enumerable:true,get:function(){return chunk7TTXS7JX_js.a}});Object.defineProperty(exports,"calculateBreachSeverity",{enumerable:true,get:function(){return chunk3YTAOT5O_js.a}});Object.defineProperty(exports,"DEFAULT_POLICY_SECTIONS",{enumerable:true,get:function(){return chunkD2ZKDQVL_js.c}});Object.defineProperty(exports,"DEFAULT_POLICY_VARIABLES",{enumerable:true,get:function(){return chunkD2ZKDQVL_js.d}});Object.defineProperty(exports,"createBusinessPolicyTemplate",{enumerable:true,get:function(){return chunkD2ZKDQVL_js.e}});Object.defineProperty(exports,"findUnfilledTokens",{enumerable:true,get:function(){return chunkD2ZKDQVL_js.a}});Object.defineProperty(exports,"generatePolicyText",{enumerable:true,get:function(){return chunkD2ZKDQVL_js.b}});Object.defineProperty(exports,"assemblePolicy",{enumerable:true,get:function(){return chunk6LJHLE6G_js.c}});Object.defineProperty(exports,"createDefaultContext",{enumerable:true,get:function(){return chunk6LJHLE6G_js.e}});Object.defineProperty(exports,"evaluatePolicyCompliance",{enumerable:true,get:function(){return chunk6LJHLE6G_js.f}});Object.defineProperty(exports,"assessTransferRisk",{enumerable:true,get:function(){return chunkYFBDJ4FH_js.h}});Object.defineProperty(exports,"getTransferMechanismDescription",{enumerable:true,get:function(){return chunkYFBDJ4FH_js.f}});Object.defineProperty(exports,"isNDPCApprovalRequired",{enumerable:true,get:function(){return chunkYFBDJ4FH_js.e}});Object.defineProperty(exports,"validateTransfer",{enumerable:true,get:function(){return chunkYFBDJ4FH_js.g}});Object.defineProperty(exports,"assessComplianceGaps",{enumerable:true,get:function(){return chunkWZYCBW2R_js.c}});Object.defineProperty(exports,"generateLawfulBasisSummary",{enumerable:true,get:function(){return chunkWZYCBW2R_js.d}});Object.defineProperty(exports,"getLawfulBasisDescription",{enumerable:true,get:function(){return chunkWZYCBW2R_js.b}});Object.defineProperty(exports,"validateProcessingActivity",{enumerable:true,get:function(){return chunkWZYCBW2R_js.a}});Object.defineProperty(exports,"exportROPAToCSV",{enumerable:true,get:function(){return chunk4CVBQC66_js.c}});Object.defineProperty(exports,"generateROPASummary",{enumerable:true,get:function(){return chunk4CVBQC66_js.b}});Object.defineProperty(exports,"identifyComplianceGaps",{enumerable:true,get:function(){return chunk4CVBQC66_js.d}});Object.defineProperty(exports,"validateProcessingRecord",{enumerable:true,get:function(){return chunk4CVBQC66_js.a}});Object.defineProperty(exports,"appendAuditEntry",{enumerable:true,get:function(){return chunk3IA3KDII_js.c}});Object.defineProperty(exports,"createAuditEntry",{enumerable:true,get:function(){return chunk3IA3KDII_js.a}});Object.defineProperty(exports,"getAuditLog",{enumerable:true,get:function(){return chunk3IA3KDII_js.b}});Object.defineProperty(exports,"validateConsentOptionsStructured",{enumerable:true,get:function(){return chunkDKLJ5DYN_js.b}});Object.defineProperty(exports,"validateConsentStructured",{enumerable:true,get:function(){return chunkDKLJ5DYN_js.a}});Object.defineProperty(exports,"sanitizeInput",{enumerable:true,get:function(){return chunkUXUMYP4L_js.a}});Object.defineProperty(exports,"formatDSRRequestStructured",{enumerable:true,get:function(){return chunkR2ZZMATR_js.b}});Object.defineProperty(exports,"validateDsrSubmissionStructured",{enumerable:true,get:function(){return chunkR2ZZMATR_js.a}});Object.defineProperty(exports,"assessDPIARisk",{enumerable:true,get:function(){return chunkTQZWJGJ2_js.a}});Object.defineProperty(exports,"LEGAL_DISCLAIMER_LONG",{enumerable:true,get:function(){return chunkZVOIR4QH_js.b}});Object.defineProperty(exports,"LEGAL_DISCLAIMER_SHORT",{enumerable:true,get:function(){return chunkZVOIR4QH_js.a}});Object.defineProperty(exports,"legalDisclaimerBlock",{enumerable:true,get:function(){return chunkZVOIR4QH_js.c}});Object.defineProperty(exports,"NDPRProvider",{enumerable:true,get:function(){return chunkI5ZDNSX5_js.a}});Object.defineProperty(exports,"useNDPRConfig",{enumerable:true,get:function(){return chunkI5ZDNSX5_js.b}});Object.defineProperty(exports,"useNDPRLocale",{enumerable:true,get:function(){return chunkI5ZDNSX5_js.c}});Object.defineProperty(exports,"defaultLocale",{enumerable:true,get:function(){return chunk7563FVMY_js.a}});Object.defineProperty(exports,"mergeLocale",{enumerable:true,get:function(){return chunk7563FVMY_js.b}});
|
package/dist/core.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{e as arabicLocale,f as frenchLocale,c as hausaLocale,b as igboLocale,d as pidginLocale,a as yorubaLocale}from'./chunk-KUI5W44P.mjs';export{a as ORG_POLICY_TEMPLATE_REGISTRY,b as createOrgTemplate,b as templateContextFor}from'./chunk-CWY2FMIC.mjs';export{
|
|
1
|
+
export{e as arabicLocale,f as frenchLocale,c as hausaLocale,b as igboLocale,d as pidginLocale,a as yorubaLocale}from'./chunk-KUI5W44P.mjs';export{a as ORG_POLICY_TEMPLATE_REGISTRY,b as createOrgTemplate,b as templateContextFor}from'./chunk-CWY2FMIC.mjs';export{c as DEFAULT_DCPMI_FEES_NGN,b as DEFAULT_DCPMI_THRESHOLDS,a as assessBreachNotification,d as classifyDCPMI,e as generateComplianceAuditReturn}from'./chunk-KOHFQIV4.mjs';export{a as getComplianceScore}from'./chunk-6A7M4CGJ.mjs';export{a as calculateBreachSeverity}from'./chunk-WTGKZX7J.mjs';export{c as DEFAULT_POLICY_SECTIONS,d as DEFAULT_POLICY_VARIABLES,e as createBusinessPolicyTemplate,a as findUnfilledTokens,b as generatePolicyText}from'./chunk-NBQQ2GN3.mjs';export{c as assemblePolicy,e as createDefaultContext,f as evaluatePolicyCompliance}from'./chunk-BIJSMSUU.mjs';export{h as assessTransferRisk,f as getTransferMechanismDescription,e as isNDPCApprovalRequired,g as validateTransfer}from'./chunk-7BJXI2HI.mjs';export{c as assessComplianceGaps,d as generateLawfulBasisSummary,b as getLawfulBasisDescription,a as validateProcessingActivity}from'./chunk-LWIKDDSU.mjs';export{c as exportROPAToCSV,b as generateROPASummary,d as identifyComplianceGaps,a as validateProcessingRecord}from'./chunk-XP5PL6K7.mjs';export{c as appendAuditEntry,a as createAuditEntry,b as getAuditLog}from'./chunk-V7UFP6QU.mjs';export{b as validateConsentOptionsStructured,a as validateConsentStructured}from'./chunk-R3ZKV2J7.mjs';export{a as sanitizeInput}from'./chunk-EWVK45Z3.mjs';export{b as formatDSRRequestStructured,a as validateDsrSubmissionStructured}from'./chunk-RRVML7CU.mjs';export{a as assessDPIARisk}from'./chunk-LRRENTT5.mjs';export{b as LEGAL_DISCLAIMER_LONG,a as LEGAL_DISCLAIMER_SHORT,c as legalDisclaimerBlock}from'./chunk-ITCY2Z66.mjs';export{a as NDPRProvider,b as useNDPRConfig,c as useNDPRLocale}from'./chunk-PHA3YMFO.mjs';export{a as defaultLocale,b as mergeLocale}from'./chunk-5LJ652AH.mjs';import'./chunk-ZJYULEER.mjs';
|