@tantainnovative/ndpr-toolkit 3.5.5 → 3.6.1

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.
@@ -0,0 +1,203 @@
1
+ import React__default from 'react';
2
+
3
+ /** A user-defined section added to the policy outside the generated ones. */
4
+ declare interface CustomSection {
5
+ id: string;
6
+ title: string;
7
+ content: string;
8
+ order: number;
9
+ required: false;
10
+ }
11
+
12
+ /** A logical category of personal data the organisation may collect. */
13
+ declare interface DataCategory {
14
+ /** Machine-readable identifier. */
15
+ id: string;
16
+ /** Human-readable label shown in the wizard. */
17
+ label: string;
18
+ /** Grouping for display and compliance checks. */
19
+ group: 'identity' | 'financial' | 'behavioral' | 'sensitive' | 'children';
20
+ /** Specific data points within this category. */
21
+ dataPoints: string[];
22
+ /** Whether this category is currently selected by the user. */
23
+ selected: boolean;
24
+ }
25
+
26
+ /**
27
+ * Policy engine types for the adaptive privacy policy generator.
28
+ * These types power the wizard-driven policy builder, compliance checker,
29
+ * and export functionality — all aligned with the NDPA 2023.
30
+ */
31
+
32
+ /** Industry verticals with sector-specific compliance requirements. */
33
+ declare type Industry = 'fintech' | 'healthcare' | 'ecommerce' | 'saas' | 'education' | 'government' | 'other';
34
+
35
+ export declare const NDPRPrivacyPolicy: React__default.FC<NDPRPrivacyPolicyProps>;
36
+
37
+ export declare interface NDPRPrivacyPolicyProps {
38
+ adapter?: StorageAdapter<PolicyDraft>;
39
+ onComplete?: (policy: PrivacyPolicy) => void;
40
+ classNames?: Record<string, string>;
41
+ unstyled?: boolean;
42
+ }
43
+
44
+ /**
45
+ * Represents organization information for a privacy policy
46
+ */
47
+ declare interface OrganizationInfo {
48
+ /** Name of the organization */
49
+ name: string;
50
+ /** Website URL of the organization */
51
+ website: string;
52
+ /** Contact email for privacy inquiries */
53
+ privacyEmail: string;
54
+ /** Physical address of the organization */
55
+ address?: string;
56
+ /** Phone number for privacy inquiries */
57
+ privacyPhone?: string;
58
+ /** Name of the Data Protection Officer */
59
+ dpoName?: string;
60
+ /** Email of the Data Protection Officer */
61
+ dpoEmail?: string;
62
+ /** Industry or sector of the organization */
63
+ industry?: string;
64
+ /** NDPC registration number (if registered) */
65
+ ndpcRegistrationNumber?: string;
66
+ }
67
+
68
+ /** Organisation size tiers — affects complexity of generated language. */
69
+ declare type OrgSize = 'startup' | 'midsize' | 'enterprise';
70
+
71
+ /** Represents an in-progress policy being built in the wizard. */
72
+ declare interface PolicyDraft {
73
+ /** Unique identifier for the draft. */
74
+ id: string;
75
+ /** The template context driving section generation. */
76
+ templateContext: TemplateContext;
77
+ /** Custom sections added by the user. */
78
+ customSections: CustomSection[];
79
+ /** Per-section content overrides keyed by section id. */
80
+ sectionOverrides: Record<string, string>;
81
+ /** Ordered list of section ids defining the final order. */
82
+ sectionOrder: string[];
83
+ /** Current wizard step (0-indexed). */
84
+ currentStep: number;
85
+ /** Timestamp of the last save. */
86
+ lastSavedAt: number;
87
+ /** The draft is always in "draft" status until finalised. */
88
+ status: 'draft';
89
+ }
90
+
91
+ /**
92
+ * Privacy policy types aligned with NDPA 2023
93
+ * Privacy policies must clearly inform data subjects of their rights under the NDPA
94
+ */
95
+ /**
96
+ * Represents a section in a privacy policy
97
+ */
98
+ declare interface PolicySection {
99
+ /** Unique identifier for the section */
100
+ id: string;
101
+ /** Title of the section */
102
+ title: string;
103
+ /** Description of the section */
104
+ description?: string;
105
+ /** Order of the section in the policy */
106
+ order?: number;
107
+ /** Whether the section is required by NDPA */
108
+ required: boolean;
109
+ /** Template text for the section */
110
+ template: string;
111
+ /**
112
+ * Default content for the section (legacy field)
113
+ * @deprecated Use template instead
114
+ */
115
+ defaultContent?: string;
116
+ /**
117
+ * Custom content for the section (overrides default content)
118
+ * @deprecated Use template instead
119
+ */
120
+ customContent?: string;
121
+ /** Whether the section is included in the policy */
122
+ included: boolean;
123
+ /** Variables that can be used in the section content */
124
+ variables?: string[];
125
+ }
126
+
127
+ /**
128
+ * Represents a generated privacy policy
129
+ */
130
+ declare interface PrivacyPolicy {
131
+ /** Unique identifier for the policy */
132
+ id: string;
133
+ /** Title of the policy */
134
+ title: string;
135
+ /** Template used to generate the policy */
136
+ templateId: string;
137
+ /** Organization information */
138
+ organizationInfo: OrganizationInfo;
139
+ /** Sections of the policy */
140
+ sections: PolicySection[];
141
+ /** Values for the variables used in the policy */
142
+ variableValues: Record<string, string>;
143
+ /** Effective date of the policy */
144
+ effectiveDate: number;
145
+ /** Last updated date of the policy */
146
+ lastUpdated: number;
147
+ /** Version of the policy */
148
+ version: string;
149
+ /**
150
+ * Applicable legal frameworks
151
+ */
152
+ applicableFrameworks?: ('ndpa' | 'ndpr' | 'gdpr' | 'ccpa')[];
153
+ }
154
+
155
+ /** Lawful processing purposes recognised under the NDPA. */
156
+ declare type ProcessingPurpose = 'service_delivery' | 'marketing' | 'analytics' | 'research' | 'legal_compliance' | 'fraud_prevention';
157
+
158
+ declare interface StorageAdapter<T = unknown> {
159
+ /** Load persisted data. Called once on hook mount. */
160
+ load(): T | null | Promise<T | null>;
161
+ /** Persist data. Called on every state change. */
162
+ save(data: T): void | Promise<void>;
163
+ /** Clear persisted data. Called on reset. */
164
+ remove(): void | Promise<void>;
165
+ }
166
+
167
+ /** Full context used to generate an adaptive privacy policy. */
168
+ declare interface TemplateContext {
169
+ /** Organisation details, extended with industry and size. */
170
+ org: OrganizationInfo & {
171
+ industry: Industry;
172
+ orgSize: OrgSize;
173
+ country: string;
174
+ };
175
+ /** Data categories the organisation collects. */
176
+ dataCategories: DataCategory[];
177
+ /** Processing purposes relevant to the organisation. */
178
+ purposes: ProcessingPurpose[];
179
+ /** Whether the organisation processes children's data. */
180
+ hasChildrenData: boolean;
181
+ /** Whether the organisation processes sensitive/special-category data. */
182
+ hasSensitiveData: boolean;
183
+ /** Whether the organisation processes financial data. */
184
+ hasFinancialData: boolean;
185
+ /** Whether data is transferred outside Nigeria. */
186
+ hasCrossBorderTransfer: boolean;
187
+ /** Whether automated decision-making or profiling is used. */
188
+ hasAutomatedDecisions: boolean;
189
+ /** Third-party processors that receive personal data. */
190
+ thirdPartyProcessors: ThirdPartyProcessor[];
191
+ }
192
+
193
+ /** A third-party entity that processes data on behalf of the organisation. */
194
+ declare interface ThirdPartyProcessor {
195
+ /** Name of the third party. */
196
+ name: string;
197
+ /** Purpose of sharing data with this processor. */
198
+ purpose: string;
199
+ /** Country where the processor is located. */
200
+ country: string;
201
+ }
202
+
203
+ export { }
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ 'use strict';var chunkW7RBGZCC_js=require('./chunk-W7RBGZCC.js');require('./chunk-I2LMQWK3.js'),require('./chunk-UI536RU2.js'),require('./chunk-N3MQQUQP.js'),require('./chunk-Q64735OC.js'),require('./chunk-ZVOIR4QH.js'),require('./chunk-AME4HJR4.js'),require('./chunk-VWED6UTN.js'),require('./chunk-RFPLZDIO.js');Object.defineProperty(exports,"NDPRPrivacyPolicy",{enumerable:true,get:function(){return chunkW7RBGZCC_js.a}});
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ export{a as NDPRPrivacyPolicy}from'./chunk-RV2VMWZJ.mjs';import'./chunk-BNHQFZHL.mjs';import'./chunk-O6CUBNXK.mjs';import'./chunk-AOHKVFAS.mjs';import'./chunk-RMQ7OLNY.mjs';import'./chunk-ITCY2Z66.mjs';import'./chunk-SFGW37LE.mjs';import'./chunk-DBZSN4WP.mjs';import'./chunk-ZJYULEER.mjs';
@@ -561,6 +561,35 @@ export declare const NDPRComplianceDashboard: React__default.FC<NDPRDashboardPre
561
561
 
562
562
  export declare const NDPRConsent: React__default.FC<NDPRConsentProps>;
563
563
 
564
+ /**
565
+ * UX copy overrides for the NDPRConsent preset. Pass any subset to
566
+ * replace the default text without dropping to the lower-level
567
+ * `<ConsentBanner>` API. Strings you omit fall back to the toolkit
568
+ * defaults (which already cite NDPA Section 26).
569
+ *
570
+ * @example
571
+ * <NDPRConsent copy={{
572
+ * title: 'Cookie preferences',
573
+ * description: 'Acme uses cookies to keep you signed in and improve our store.',
574
+ * acceptAll: 'Allow all',
575
+ * rejectAll: 'Only essentials',
576
+ * }} />
577
+ */
578
+ declare interface NDPRConsentCopy {
579
+ /** Banner heading. Default: "We Value Your Privacy" */
580
+ title?: string;
581
+ /** Body paragraph under the heading. Default cites NDPA Section 26. */
582
+ description?: string;
583
+ /** Primary CTA — accepts all categories. Default: "Accept All" */
584
+ acceptAll?: string;
585
+ /** Secondary CTA — rejects all non-essential categories. Default: "Reject All" */
586
+ rejectAll?: string;
587
+ /** Tertiary CTA — opens the per-category controls. Default: "Customize" */
588
+ customize?: string;
589
+ /** Submit button on the per-category panel. Default: "Save Preferences" */
590
+ save?: string;
591
+ }
592
+
564
593
  export declare interface NDPRConsentProps {
565
594
  extraOptions?: ConsentOption[];
566
595
  options?: ConsentOption[];
@@ -569,6 +598,11 @@ export declare interface NDPRConsentProps {
569
598
  classNames?: ConsentBannerClassNames;
570
599
  unstyled?: boolean;
571
600
  onSave?: (settings: ConsentSettings) => void;
601
+ /**
602
+ * UX copy overrides — see {@link NDPRConsentCopy}. Lets you brand the
603
+ * banner without dropping to the lower-level `<ConsentBanner>` API.
604
+ */
605
+ copy?: NDPRConsentCopy;
572
606
  }
573
607
 
574
608
  export declare const NDPRCrossBorder: React__default.FC<NDPRCrossBorderProps>;
@@ -659,6 +693,45 @@ export declare interface NDPRSubjectRightsProps {
659
693
  classNames?: DSRRequestFormClassNames;
660
694
  unstyled?: boolean;
661
695
  onSubmit?: (data: DSRFormSubmission) => void;
696
+ /**
697
+ * Public-form mode. Use when the form should submit to your existing
698
+ * backend workflow instead of being state-managed by an adapter.
699
+ *
700
+ * When `submitTo` is set:
701
+ * - the form does NOT require an `adapter`
702
+ * - on submit, the toolkit POSTs the JSON-serialised `DSRFormSubmission`
703
+ * to this URL (with `Content-Type: application/json`)
704
+ * - your `onSubmit` callback still fires (after the POST resolves)
705
+ * - submit failures are surfaced via `onSubmitError`
706
+ *
707
+ * For more control over headers, credentials, or retry behaviour, build
708
+ * an `apiAdapter` (which now supports CSRF, retry, and error hooks in
709
+ * 3.6.0) and pass that as `adapter` instead. `submitTo` is the
710
+ * fire-and-forget shortcut for public forms.
711
+ *
712
+ * @example
713
+ * <NDPRSubjectRights submitTo="/api/dsr" />
714
+ */
715
+ submitTo?: string;
716
+ /**
717
+ * Fetch options for the `submitTo` POST. Useful for adding `credentials`
718
+ * (cookies/auth), `X-CSRF-Token`, or any other header your backend
719
+ * requires. Ignored unless `submitTo` is set.
720
+ *
721
+ * @default { credentials: 'same-origin' }
722
+ */
723
+ submitOptions?: {
724
+ headers?: Record<string, string> | (() => Record<string, string>);
725
+ credentials?: RequestCredentials;
726
+ };
727
+ /**
728
+ * Called when a `submitTo` POST fails (network error or non-2xx
729
+ * response). Receives the underlying error or Response.
730
+ */
731
+ onSubmitError?: (ctx: {
732
+ error?: unknown;
733
+ response?: Response;
734
+ }) => void;
662
735
  }
663
736
 
664
737
  /**
package/dist/presets.d.ts CHANGED
@@ -561,6 +561,35 @@ export declare const NDPRComplianceDashboard: React__default.FC<NDPRDashboardPre
561
561
 
562
562
  export declare const NDPRConsent: React__default.FC<NDPRConsentProps>;
563
563
 
564
+ /**
565
+ * UX copy overrides for the NDPRConsent preset. Pass any subset to
566
+ * replace the default text without dropping to the lower-level
567
+ * `<ConsentBanner>` API. Strings you omit fall back to the toolkit
568
+ * defaults (which already cite NDPA Section 26).
569
+ *
570
+ * @example
571
+ * <NDPRConsent copy={{
572
+ * title: 'Cookie preferences',
573
+ * description: 'Acme uses cookies to keep you signed in and improve our store.',
574
+ * acceptAll: 'Allow all',
575
+ * rejectAll: 'Only essentials',
576
+ * }} />
577
+ */
578
+ declare interface NDPRConsentCopy {
579
+ /** Banner heading. Default: "We Value Your Privacy" */
580
+ title?: string;
581
+ /** Body paragraph under the heading. Default cites NDPA Section 26. */
582
+ description?: string;
583
+ /** Primary CTA — accepts all categories. Default: "Accept All" */
584
+ acceptAll?: string;
585
+ /** Secondary CTA — rejects all non-essential categories. Default: "Reject All" */
586
+ rejectAll?: string;
587
+ /** Tertiary CTA — opens the per-category controls. Default: "Customize" */
588
+ customize?: string;
589
+ /** Submit button on the per-category panel. Default: "Save Preferences" */
590
+ save?: string;
591
+ }
592
+
564
593
  export declare interface NDPRConsentProps {
565
594
  extraOptions?: ConsentOption[];
566
595
  options?: ConsentOption[];
@@ -569,6 +598,11 @@ export declare interface NDPRConsentProps {
569
598
  classNames?: ConsentBannerClassNames;
570
599
  unstyled?: boolean;
571
600
  onSave?: (settings: ConsentSettings) => void;
601
+ /**
602
+ * UX copy overrides — see {@link NDPRConsentCopy}. Lets you brand the
603
+ * banner without dropping to the lower-level `<ConsentBanner>` API.
604
+ */
605
+ copy?: NDPRConsentCopy;
572
606
  }
573
607
 
574
608
  export declare const NDPRCrossBorder: React__default.FC<NDPRCrossBorderProps>;
@@ -659,6 +693,45 @@ export declare interface NDPRSubjectRightsProps {
659
693
  classNames?: DSRRequestFormClassNames;
660
694
  unstyled?: boolean;
661
695
  onSubmit?: (data: DSRFormSubmission) => void;
696
+ /**
697
+ * Public-form mode. Use when the form should submit to your existing
698
+ * backend workflow instead of being state-managed by an adapter.
699
+ *
700
+ * When `submitTo` is set:
701
+ * - the form does NOT require an `adapter`
702
+ * - on submit, the toolkit POSTs the JSON-serialised `DSRFormSubmission`
703
+ * to this URL (with `Content-Type: application/json`)
704
+ * - your `onSubmit` callback still fires (after the POST resolves)
705
+ * - submit failures are surfaced via `onSubmitError`
706
+ *
707
+ * For more control over headers, credentials, or retry behaviour, build
708
+ * an `apiAdapter` (which now supports CSRF, retry, and error hooks in
709
+ * 3.6.0) and pass that as `adapter` instead. `submitTo` is the
710
+ * fire-and-forget shortcut for public forms.
711
+ *
712
+ * @example
713
+ * <NDPRSubjectRights submitTo="/api/dsr" />
714
+ */
715
+ submitTo?: string;
716
+ /**
717
+ * Fetch options for the `submitTo` POST. Useful for adding `credentials`
718
+ * (cookies/auth), `X-CSRF-Token`, or any other header your backend
719
+ * requires. Ignored unless `submitTo` is set.
720
+ *
721
+ * @default { credentials: 'same-origin' }
722
+ */
723
+ submitOptions?: {
724
+ headers?: Record<string, string> | (() => Record<string, string>);
725
+ credentials?: RequestCredentials;
726
+ };
727
+ /**
728
+ * Called when a `submitTo` POST fails (network error or non-2xx
729
+ * response). Receives the underlying error or Response.
730
+ */
731
+ onSubmitError?: (ctx: {
732
+ error?: unknown;
733
+ response?: Response;
734
+ }) => void;
662
735
  }
663
736
 
664
737
  /**
package/dist/presets.js CHANGED
@@ -1,2 +1,2 @@
1
1
  "use client";
2
- 'use strict';var chunkI2LMQWK3_js=require('./chunk-I2LMQWK3.js'),chunkNUWVPRNI_js=require('./chunk-NUWVPRNI.js'),chunkPZRQWPWD_js=require('./chunk-PZRQWPWD.js'),chunkI3Y4LOSL_js=require('./chunk-I3Y4LOSL.js'),chunk5GVMKUMP_js=require('./chunk-5GVMKUMP.js');require('./chunk-UI536RU2.js'),require('./chunk-N3MQQUQP.js');var chunkQPRYXVH2_js=require('./chunk-QPRYXVH2.js');require('./chunk-Q64735OC.js'),require('./chunk-WZYCBW2R.js'),require('./chunk-YFBDJ4FH.js'),require('./chunk-4CVBQC66.js');var chunk732C2EVN_js=require('./chunk-732C2EVN.js');require('./chunk-L2VO3MEJ.js');var chunkW47OSMT6_js=require('./chunk-W47OSMT6.js'),chunkWDDCKYWA_js=require('./chunk-WDDCKYWA.js'),chunkS6COXIZA_js=require('./chunk-S6COXIZA.js');require('./chunk-UXUMYP4L.js'),require('./chunk-ZVOIR4QH.js'),require('./chunk-AME4HJR4.js'),require('./chunk-VWED6UTN.js');var chunkRFPLZDIO_js=require('./chunk-RFPLZDIO.js'),jsxRuntime=require('react/jsx-runtime'),react=require('react');var q=[{id:"essential",label:"Essential Cookies",description:"Required for basic site functionality. Cannot be disabled.",required:true,purpose:"Site operation"},{id:"analytics",label:"Analytics",description:"Help us understand how visitors use our site to improve the experience.",required:false,purpose:"Usage analytics"},{id:"marketing",label:"Marketing",description:"Used to deliver relevant advertisements and track campaign effectiveness.",required:false,purpose:"Targeted advertising"},{id:"preferences",label:"Preferences",description:"Remember your settings and preferences for a personalised experience.",required:false,purpose:"Personalisation"}],I=({extraOptions:d=[],options:t,adapter:p,position:l="bottom",classNames:s,unstyled:c,onSave:a})=>{let u=t!=null?t:[...q,...d];return jsxRuntime.jsx(chunk732C2EVN_js.a,{options:u,onSave:f=>{p&&p.save(f),a==null||a(f);},position:l,classNames:s,unstyled:c,manageStorage:!p})};var L=[{id:"access",name:"Access My Data",description:"Request a copy of your personal data held by us",ndpaSection:"Section 34(1)(a)\u2013(b)",estimatedCompletionTime:30,requiresAdditionalInfo:false},{id:"rectification",name:"Correct My Data",description:"Request corrections to inaccurate personal data",ndpaSection:"Section 34(1)(c)",estimatedCompletionTime:30,requiresAdditionalInfo:true,additionalFields:[{id:"correction_details",label:"What data needs to be corrected?",type:"textarea",required:true,placeholder:"Please describe the inaccurate data and what the correct information should be"}]},{id:"erasure",name:"Delete My Data",description:"Request deletion of your personal data",ndpaSection:"Section 34(1)(d), Section 34(2)",estimatedCompletionTime:30,requiresAdditionalInfo:false},{id:"portability",name:"Export My Data",description:"Receive your data in a portable format",ndpaSection:"Section 38",estimatedCompletionTime:30,requiresAdditionalInfo:false},{id:"restrict",name:"Restrict Processing",description:"Request restriction of data processing",ndpaSection:"Section 34(1)(e)",estimatedCompletionTime:30,requiresAdditionalInfo:false},{id:"object",name:"Object to Processing",description:"Object to processing of your personal data",ndpaSection:"Section 36",estimatedCompletionTime:30,requiresAdditionalInfo:false},{id:"withdraw_consent",name:"Withdraw My Consent",description:"Withdraw consent previously given for processing",ndpaSection:"Section 35",estimatedCompletionTime:30,requiresAdditionalInfo:false}],k=({requestTypes:d=L,adapter:t,classNames:p,unstyled:l,onSubmit:s=()=>{}})=>jsxRuntime.jsx(chunkW47OSMT6_js.a,{requestTypes:d,onSubmit:a=>{t&&t.save(a),s(a);},classNames:p,unstyled:l});var _=[{id:"unauthorized_access",name:"Unauthorized Access",description:"Unauthorized access to personal data",defaultSeverity:"high"},{id:"data_loss",name:"Data Loss",description:"Loss of personal data",defaultSeverity:"high"},{id:"data_theft",name:"Data Theft",description:"Theft of personal data",defaultSeverity:"critical"},{id:"system_breach",name:"System Breach",description:"Breach of system containing personal data",defaultSeverity:"critical"},{id:"accidental_disclosure",name:"Accidental Disclosure",description:"Unintended disclosure of personal data",defaultSeverity:"medium"}],U=({categories:d=_,adapter:t,classNames:p,unstyled:l,onSubmit:s=()=>{}})=>jsxRuntime.jsx(chunkS6COXIZA_js.a,{categories:d,onSubmit:a=>{t&&t.save(a),s(a);},classNames:p,unstyled:l});var E=d=>jsxRuntime.jsx(chunkI2LMQWK3_js.a,chunkRFPLZDIO_js.a({},d));var Y=[{id:"project_overview",title:"Project Overview",description:"Provide basic details about the processing activity being assessed.",order:0,questions:[{id:"project_name",text:"What is the name of the project or processing activity?",type:"text",required:true},{id:"project_description",text:"Describe the nature and purpose of the processing.",guidance:"Include what personal data will be collected, why it is needed, and how it will be used.",type:"textarea",required:true},{id:"data_controller",text:"Who is the data controller responsible for this processing?",type:"text",required:true}]},{id:"necessity",title:"Necessity & Proportionality",description:"Assess whether the processing is necessary and proportionate to the purposes.",order:1,questions:[{id:"lawful_basis",text:"What is the lawful basis for processing under the NDPA 2023?",type:"select",required:true,options:[{value:"consent",label:"Consent (Section 25(1)(a))"},{value:"contract",label:"Contract (Section 25(1)(b))"},{value:"legal_obligation",label:"Legal Obligation (Section 25(1)(c))"},{value:"vital_interests",label:"Vital Interests (Section 25(1)(d))"},{value:"public_task",label:"Public Task (Section 25(1)(e))"},{value:"legitimate_interests",label:"Legitimate Interests (Section 25(1)(f))"}]},{id:"data_minimisation",text:"Is the processing limited to what is necessary for the specified purpose?",type:"radio",required:true,options:[{value:"yes",label:"Yes \u2014 only minimum data is collected",riskLevel:"low"},{value:"partial",label:"Partially \u2014 some additional data may be collected",riskLevel:"medium"},{value:"no",label:"No \u2014 more data is collected than strictly necessary",riskLevel:"high"}]}]},{id:"risk_identification",title:"Risk Identification",description:"Identify and assess risks to data subjects arising from the processing.",order:2,questions:[{id:"sensitive_data",text:"Does the processing involve sensitive personal data (e.g., health, biometric, financial, children's data)?",type:"radio",required:true,options:[{value:"no",label:"No sensitive data",riskLevel:"low"},{value:"yes_protected",label:"Yes, with appropriate safeguards",riskLevel:"medium"},{value:"yes_unprotected",label:"Yes, without adequate safeguards",riskLevel:"high"}]},{id:"scale",text:"What is the scale of processing?",type:"radio",required:true,options:[{value:"small",label:"Small scale (fewer than 1,000 individuals)",riskLevel:"low"},{value:"medium",label:"Medium scale (1,000 to 100,000 individuals)",riskLevel:"medium"},{value:"large",label:"Large scale (over 100,000 individuals)",riskLevel:"high"}]},{id:"cross_border",text:"Will data be transferred outside Nigeria?",type:"radio",required:true,options:[{value:"no",label:"No international transfers",riskLevel:"low"},{value:"adequate",label:"Yes, to countries with adequate protection",riskLevel:"medium"},{value:"inadequate",label:"Yes, to countries without adequate protection",riskLevel:"high"}]}]},{id:"mitigation",title:"Risk Mitigation & Measures",description:"Document the measures taken to address identified risks.",order:3,questions:[{id:"security_measures",text:"What technical and organisational security measures are in place?",guidance:"Include encryption, access controls, pseudonymisation, staff training, etc.",type:"textarea",required:true},{id:"retention_period",text:"What is the data retention period?",guidance:"Specify how long data will be kept and the criteria used to determine this.",type:"text",required:true},{id:"dpo_consulted",text:"Has the Data Protection Officer (DPO) been consulted on this assessment?",type:"radio",required:false,options:[{value:"yes",label:"Yes",riskLevel:"low"},{value:"no",label:"No",riskLevel:"medium"},{value:"na",label:"Not applicable \u2014 no DPO appointed",riskLevel:"medium"}]}]}],z=({sections:d=Y,adapter:t,classNames:p,unstyled:l,onComplete:s=()=>{}})=>{let[c,a]=react.useState({}),[u,P]=react.useState(0),f=(i,T)=>{a(B=>chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a({},B),{[i]:T}));},e=()=>{u<d.length-1?P(i=>i+1):(t&&t.save(c),s(c));},r=()=>{u>0&&P(i=>i-1);},o=Math.round((u+1)/d.length*100);return jsxRuntime.jsx(chunkWDDCKYWA_js.a,{sections:d,answers:c,onAnswerChange:f,currentSectionIndex:u,onNextSection:e,onPrevSection:r,progress:o,classNames:p,unstyled:l})};var V=({initialActivities:d=[],adapter:t,classNames:p,unstyled:l})=>{let[s,c]=react.useState(()=>{if(t){let e=t.load();if(e&&!(e instanceof Promise))return e}return d}),a=e=>{t&&t.save(e);};return jsxRuntime.jsx(chunkPZRQWPWD_js.a,{activities:s,onAddActivity:e=>{let r=Date.now(),o=chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a({},e),{id:`activity-${r}`,createdAt:r,updatedAt:r}),i=[...s,o];c(i),a(i);},onUpdateActivity:(e,r)=>{let o=s.map(i=>i.id===e?chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a(chunkRFPLZDIO_js.a({},i),r),{updatedAt:Date.now()}):i);c(o),a(o);},onArchiveActivity:e=>{let r=s.map(o=>o.id===e?chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a({},o),{status:"inactive",updatedAt:Date.now()}):o);c(r),a(r);},classNames:p,unstyled:l})};var G=({initialTransfers:d=[],adapter:t,classNames:p,unstyled:l})=>{let[s,c]=react.useState(()=>{if(t){let e=t.load();if(e&&!(e instanceof Promise))return e}return d}),a=e=>{t&&t.save(e);};return jsxRuntime.jsx(chunkI3Y4LOSL_js.a,{transfers:s,onAddTransfer:e=>{let r=Date.now(),o=chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a({},e),{id:`transfer-${r}`,createdAt:r,updatedAt:r}),i=[...s,o];c(i),a(i);},onUpdateTransfer:(e,r)=>{let o=s.map(i=>i.id===e?chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a(chunkRFPLZDIO_js.a({},i),r),{updatedAt:Date.now()}):i);c(o),a(o);},onRemoveTransfer:e=>{let r=s.filter(o=>o.id!==e);c(r),a(r);},classNames:p,unstyled:l})};var Z={id:"ndpr-ropa-default",organizationName:"Your Organisation",organizationContact:"",organizationAddress:"",records:[],lastUpdated:Date.now(),version:"1.0"},ee=({initialData:d,adapter:t,classNames:p,unstyled:l})=>{let[s,c]=react.useState(d!=null?d:Z);react.useEffect(()=>{if(!t)return;let e=false;return chunkRFPLZDIO_js.d(null,null,function*(){let o=yield t.load();!e&&o&&c(o);}),()=>{e=true;}},[t]);let a=e=>{t&&t.save(e);};return jsxRuntime.jsx(chunk5GVMKUMP_js.a,{ropa:s,onAddRecord:e=>{let r=chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a({},s),{records:[...s.records,e],lastUpdated:Date.now()});c(r),a(r);},onUpdateRecord:(e,r)=>{let o=chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a({},s),{records:s.records.map(i=>i.id===e?chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a(chunkRFPLZDIO_js.a({},i),r),{updatedAt:Date.now()}):i),lastUpdated:Date.now()});c(o),a(o);},onArchiveRecord:e=>{let r=chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a({},s),{records:s.records.map(o=>o.id===e?chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a({},o),{status:"archived",updatedAt:Date.now()}):o),lastUpdated:Date.now()});c(r),a(r);},classNames:p,unstyled:l})};var re=p=>{var l=p,{input:d}=l,t=chunkRFPLZDIO_js.c(l,["input"]);let s=chunkQPRYXVH2_js.a(d);return jsxRuntime.jsx(chunkNUWVPRNI_js.a,chunkRFPLZDIO_js.a({report:s},t))};exports.NDPRBreachReport=U;exports.NDPRComplianceDashboard=re;exports.NDPRConsent=I;exports.NDPRCrossBorder=G;exports.NDPRDPIA=z;exports.NDPRLawfulBasis=V;exports.NDPRPrivacyPolicy=E;exports.NDPRROPA=ee;exports.NDPRSubjectRights=k;
2
+ 'use strict';var chunkW7RBGZCC_js=require('./chunk-W7RBGZCC.js');require('./chunk-I2LMQWK3.js');var chunkV3RYHNHN_js=require('./chunk-V3RYHNHN.js'),chunkRXZFYBUJ_js=require('./chunk-RXZFYBUJ.js'),chunkNUWVPRNI_js=require('./chunk-NUWVPRNI.js'),chunkPZRQWPWD_js=require('./chunk-PZRQWPWD.js'),chunkI3Y4LOSL_js=require('./chunk-I3Y4LOSL.js'),chunk5GVMKUMP_js=require('./chunk-5GVMKUMP.js');require('./chunk-UI536RU2.js'),require('./chunk-N3MQQUQP.js');var chunkQPRYXVH2_js=require('./chunk-QPRYXVH2.js');require('./chunk-Q64735OC.js'),require('./chunk-WZYCBW2R.js'),require('./chunk-YFBDJ4FH.js'),require('./chunk-4CVBQC66.js'),require('./chunk-732C2EVN.js'),require('./chunk-L2VO3MEJ.js'),require('./chunk-W47OSMT6.js');var chunkWDDCKYWA_js=require('./chunk-WDDCKYWA.js'),chunkS6COXIZA_js=require('./chunk-S6COXIZA.js');require('./chunk-UXUMYP4L.js'),require('./chunk-ZVOIR4QH.js'),require('./chunk-AME4HJR4.js'),require('./chunk-VWED6UTN.js');var chunkRFPLZDIO_js=require('./chunk-RFPLZDIO.js'),jsxRuntime=require('react/jsx-runtime'),react=require('react');var L=[{id:"unauthorized_access",name:"Unauthorized Access",description:"Unauthorized access to personal data",defaultSeverity:"high"},{id:"data_loss",name:"Data Loss",description:"Loss of personal data",defaultSeverity:"high"},{id:"data_theft",name:"Data Theft",description:"Theft of personal data",defaultSeverity:"critical"},{id:"system_breach",name:"System Breach",description:"Breach of system containing personal data",defaultSeverity:"critical"},{id:"accidental_disclosure",name:"Accidental Disclosure",description:"Unintended disclosure of personal data",defaultSeverity:"medium"}],I=({categories:c=L,adapter:s,classNames:u,unstyled:p,onSubmit:o=()=>{}})=>jsxRuntime.jsx(chunkS6COXIZA_js.a,{categories:c,onSubmit:d=>{s&&s.save(d),o(d);},classNames:u,unstyled:p});var k=[{id:"project_overview",title:"Project Overview",description:"Provide basic details about the processing activity being assessed.",order:0,questions:[{id:"project_name",text:"What is the name of the project or processing activity?",type:"text",required:true},{id:"project_description",text:"Describe the nature and purpose of the processing.",guidance:"Include what personal data will be collected, why it is needed, and how it will be used.",type:"textarea",required:true},{id:"data_controller",text:"Who is the data controller responsible for this processing?",type:"text",required:true}]},{id:"necessity",title:"Necessity & Proportionality",description:"Assess whether the processing is necessary and proportionate to the purposes.",order:1,questions:[{id:"lawful_basis",text:"What is the lawful basis for processing under the NDPA 2023?",type:"select",required:true,options:[{value:"consent",label:"Consent (Section 25(1)(a))"},{value:"contract",label:"Contract (Section 25(1)(b))"},{value:"legal_obligation",label:"Legal Obligation (Section 25(1)(c))"},{value:"vital_interests",label:"Vital Interests (Section 25(1)(d))"},{value:"public_task",label:"Public Task (Section 25(1)(e))"},{value:"legitimate_interests",label:"Legitimate Interests (Section 25(1)(f))"}]},{id:"data_minimisation",text:"Is the processing limited to what is necessary for the specified purpose?",type:"radio",required:true,options:[{value:"yes",label:"Yes \u2014 only minimum data is collected",riskLevel:"low"},{value:"partial",label:"Partially \u2014 some additional data may be collected",riskLevel:"medium"},{value:"no",label:"No \u2014 more data is collected than strictly necessary",riskLevel:"high"}]}]},{id:"risk_identification",title:"Risk Identification",description:"Identify and assess risks to data subjects arising from the processing.",order:2,questions:[{id:"sensitive_data",text:"Does the processing involve sensitive personal data (e.g., health, biometric, financial, children's data)?",type:"radio",required:true,options:[{value:"no",label:"No sensitive data",riskLevel:"low"},{value:"yes_protected",label:"Yes, with appropriate safeguards",riskLevel:"medium"},{value:"yes_unprotected",label:"Yes, without adequate safeguards",riskLevel:"high"}]},{id:"scale",text:"What is the scale of processing?",type:"radio",required:true,options:[{value:"small",label:"Small scale (fewer than 1,000 individuals)",riskLevel:"low"},{value:"medium",label:"Medium scale (1,000 to 100,000 individuals)",riskLevel:"medium"},{value:"large",label:"Large scale (over 100,000 individuals)",riskLevel:"high"}]},{id:"cross_border",text:"Will data be transferred outside Nigeria?",type:"radio",required:true,options:[{value:"no",label:"No international transfers",riskLevel:"low"},{value:"adequate",label:"Yes, to countries with adequate protection",riskLevel:"medium"},{value:"inadequate",label:"Yes, to countries without adequate protection",riskLevel:"high"}]}]},{id:"mitigation",title:"Risk Mitigation & Measures",description:"Document the measures taken to address identified risks.",order:3,questions:[{id:"security_measures",text:"What technical and organisational security measures are in place?",guidance:"Include encryption, access controls, pseudonymisation, staff training, etc.",type:"textarea",required:true},{id:"retention_period",text:"What is the data retention period?",guidance:"Specify how long data will be kept and the criteria used to determine this.",type:"text",required:true},{id:"dpo_consulted",text:"Has the Data Protection Officer (DPO) been consulted on this assessment?",type:"radio",required:false,options:[{value:"yes",label:"Yes",riskLevel:"low"},{value:"no",label:"No",riskLevel:"medium"},{value:"na",label:"Not applicable \u2014 no DPO appointed",riskLevel:"medium"}]}]}],_=({sections:c=k,adapter:s,classNames:u,unstyled:p,onComplete:o=()=>{}})=>{let[n,d]=react.useState({}),[m,f]=react.useState(0),P=(a,C)=>{d(S=>chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a({},S),{[a]:C}));},e=()=>{m<c.length-1?f(a=>a+1):(s&&s.save(n),o(n));},t=()=>{m>0&&f(a=>a-1);},r=Math.round((m+1)/c.length*100);return jsxRuntime.jsx(chunkWDDCKYWA_js.a,{sections:c,answers:n,onAnswerChange:P,currentSectionIndex:m,onNextSection:e,onPrevSection:t,progress:r,classNames:u,unstyled:p})};var F=({initialActivities:c=[],adapter:s,classNames:u,unstyled:p})=>{let[o,n]=react.useState(()=>{if(s){let e=s.load();if(e&&!(e instanceof Promise))return e}return c}),d=e=>{s&&s.save(e);};return jsxRuntime.jsx(chunkPZRQWPWD_js.a,{activities:o,onAddActivity:e=>{let t=Date.now(),r=chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a({},e),{id:`activity-${t}`,createdAt:t,updatedAt:t}),a=[...o,r];n(a),d(a);},onUpdateActivity:(e,t)=>{let r=o.map(a=>a.id===e?chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a(chunkRFPLZDIO_js.a({},a),t),{updatedAt:Date.now()}):a);n(r),d(r);},onArchiveActivity:e=>{let t=o.map(r=>r.id===e?chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a({},r),{status:"inactive",updatedAt:Date.now()}):r);n(t),d(t);},classNames:u,unstyled:p})};var W=({initialTransfers:c=[],adapter:s,classNames:u,unstyled:p})=>{let[o,n]=react.useState(()=>{if(s){let e=s.load();if(e&&!(e instanceof Promise))return e}return c}),d=e=>{s&&s.save(e);};return jsxRuntime.jsx(chunkI3Y4LOSL_js.a,{transfers:o,onAddTransfer:e=>{let t=Date.now(),r=chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a({},e),{id:`transfer-${t}`,createdAt:t,updatedAt:t}),a=[...o,r];n(a),d(a);},onUpdateTransfer:(e,t)=>{let r=o.map(a=>a.id===e?chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a(chunkRFPLZDIO_js.a({},a),t),{updatedAt:Date.now()}):a);n(r),d(r);},onRemoveTransfer:e=>{let t=o.filter(r=>r.id!==e);n(t),d(t);},classNames:u,unstyled:p})};var j={id:"ndpr-ropa-default",organizationName:"Your Organisation",organizationContact:"",organizationAddress:"",records:[],lastUpdated:Date.now(),version:"1.0"},V=({initialData:c,adapter:s,classNames:u,unstyled:p})=>{let[o,n]=react.useState(c!=null?c:j);react.useEffect(()=>{if(!s)return;let e=false;return chunkRFPLZDIO_js.d(null,null,function*(){let r=yield s.load();!e&&r&&n(r);}),()=>{e=true;}},[s]);let d=e=>{s&&s.save(e);};return jsxRuntime.jsx(chunk5GVMKUMP_js.a,{ropa:o,onAddRecord:e=>{let t=chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a({},o),{records:[...o.records,e],lastUpdated:Date.now()});n(t),d(t);},onUpdateRecord:(e,t)=>{let r=chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a({},o),{records:o.records.map(a=>a.id===e?chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a(chunkRFPLZDIO_js.a({},a),t),{updatedAt:Date.now()}):a),lastUpdated:Date.now()});n(r),d(r);},onArchiveRecord:e=>{let t=chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a({},o),{records:o.records.map(r=>r.id===e?chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a({},r),{status:"archived",updatedAt:Date.now()}):r),lastUpdated:Date.now()});n(t),d(t);},classNames:u,unstyled:p})};var G=u=>{var p=u,{input:c}=p,s=chunkRFPLZDIO_js.c(p,["input"]);let o=chunkQPRYXVH2_js.a(c);return jsxRuntime.jsx(chunkNUWVPRNI_js.a,chunkRFPLZDIO_js.a({report:o},s))};Object.defineProperty(exports,"NDPRPrivacyPolicy",{enumerable:true,get:function(){return chunkW7RBGZCC_js.a}});Object.defineProperty(exports,"NDPRConsent",{enumerable:true,get:function(){return chunkV3RYHNHN_js.a}});Object.defineProperty(exports,"NDPRSubjectRights",{enumerable:true,get:function(){return chunkRXZFYBUJ_js.a}});exports.NDPRBreachReport=I;exports.NDPRComplianceDashboard=G;exports.NDPRCrossBorder=W;exports.NDPRDPIA=_;exports.NDPRLawfulBasis=F;exports.NDPRROPA=V;
package/dist/presets.mjs CHANGED
@@ -1,2 +1,2 @@
1
1
  "use client";
2
- import {a as a$3}from'./chunk-BNHQFZHL.mjs';import {a as a$a}from'./chunk-ZIZL37BG.mjs';import {a as a$6}from'./chunk-COD3RMTL.mjs';import {a as a$7}from'./chunk-GTYXVAJX.mjs';import {a as a$8}from'./chunk-EXEXUAF6.mjs';import'./chunk-O6CUBNXK.mjs';import'./chunk-AOHKVFAS.mjs';import {a as a$9}from'./chunk-EFIBHKQE.mjs';import'./chunk-RMQ7OLNY.mjs';import'./chunk-LWIKDDSU.mjs';import'./chunk-7BJXI2HI.mjs';import'./chunk-XP5PL6K7.mjs';import {a}from'./chunk-BFAX7JQA.mjs';import'./chunk-YTU4FNM2.mjs';import {a as a$1}from'./chunk-XJO4DH3L.mjs';import {a as a$5}from'./chunk-ZQZJNKVB.mjs';import {a as a$2}from'./chunk-ZHFLBL63.mjs';import'./chunk-EWVK45Z3.mjs';import'./chunk-ITCY2Z66.mjs';import'./chunk-SFGW37LE.mjs';import'./chunk-DBZSN4WP.mjs';import {a as a$4,b,d,c}from'./chunk-ZJYULEER.mjs';import {jsx}from'react/jsx-runtime';import {useState,useEffect}from'react';var q=[{id:"essential",label:"Essential Cookies",description:"Required for basic site functionality. Cannot be disabled.",required:true,purpose:"Site operation"},{id:"analytics",label:"Analytics",description:"Help us understand how visitors use our site to improve the experience.",required:false,purpose:"Usage analytics"},{id:"marketing",label:"Marketing",description:"Used to deliver relevant advertisements and track campaign effectiveness.",required:false,purpose:"Targeted advertising"},{id:"preferences",label:"Preferences",description:"Remember your settings and preferences for a personalised experience.",required:false,purpose:"Personalisation"}],I=({extraOptions:d=[],options:t,adapter:p,position:l="bottom",classNames:s,unstyled:c,onSave:a$1})=>{let u=t!=null?t:[...q,...d];return jsx(a,{options:u,onSave:f=>{p&&p.save(f),a$1==null||a$1(f);},position:l,classNames:s,unstyled:c,manageStorage:!p})};var L=[{id:"access",name:"Access My Data",description:"Request a copy of your personal data held by us",ndpaSection:"Section 34(1)(a)\u2013(b)",estimatedCompletionTime:30,requiresAdditionalInfo:false},{id:"rectification",name:"Correct My Data",description:"Request corrections to inaccurate personal data",ndpaSection:"Section 34(1)(c)",estimatedCompletionTime:30,requiresAdditionalInfo:true,additionalFields:[{id:"correction_details",label:"What data needs to be corrected?",type:"textarea",required:true,placeholder:"Please describe the inaccurate data and what the correct information should be"}]},{id:"erasure",name:"Delete My Data",description:"Request deletion of your personal data",ndpaSection:"Section 34(1)(d), Section 34(2)",estimatedCompletionTime:30,requiresAdditionalInfo:false},{id:"portability",name:"Export My Data",description:"Receive your data in a portable format",ndpaSection:"Section 38",estimatedCompletionTime:30,requiresAdditionalInfo:false},{id:"restrict",name:"Restrict Processing",description:"Request restriction of data processing",ndpaSection:"Section 34(1)(e)",estimatedCompletionTime:30,requiresAdditionalInfo:false},{id:"object",name:"Object to Processing",description:"Object to processing of your personal data",ndpaSection:"Section 36",estimatedCompletionTime:30,requiresAdditionalInfo:false},{id:"withdraw_consent",name:"Withdraw My Consent",description:"Withdraw consent previously given for processing",ndpaSection:"Section 35",estimatedCompletionTime:30,requiresAdditionalInfo:false}],k=({requestTypes:d=L,adapter:t,classNames:p,unstyled:l,onSubmit:s=()=>{}})=>jsx(a$1,{requestTypes:d,onSubmit:a=>{t&&t.save(a),s(a);},classNames:p,unstyled:l});var _=[{id:"unauthorized_access",name:"Unauthorized Access",description:"Unauthorized access to personal data",defaultSeverity:"high"},{id:"data_loss",name:"Data Loss",description:"Loss of personal data",defaultSeverity:"high"},{id:"data_theft",name:"Data Theft",description:"Theft of personal data",defaultSeverity:"critical"},{id:"system_breach",name:"System Breach",description:"Breach of system containing personal data",defaultSeverity:"critical"},{id:"accidental_disclosure",name:"Accidental Disclosure",description:"Unintended disclosure of personal data",defaultSeverity:"medium"}],U=({categories:d=_,adapter:t,classNames:p,unstyled:l,onSubmit:s=()=>{}})=>jsx(a$2,{categories:d,onSubmit:a=>{t&&t.save(a),s(a);},classNames:p,unstyled:l});var E=d=>jsx(a$3,a$4({},d));var Y=[{id:"project_overview",title:"Project Overview",description:"Provide basic details about the processing activity being assessed.",order:0,questions:[{id:"project_name",text:"What is the name of the project or processing activity?",type:"text",required:true},{id:"project_description",text:"Describe the nature and purpose of the processing.",guidance:"Include what personal data will be collected, why it is needed, and how it will be used.",type:"textarea",required:true},{id:"data_controller",text:"Who is the data controller responsible for this processing?",type:"text",required:true}]},{id:"necessity",title:"Necessity & Proportionality",description:"Assess whether the processing is necessary and proportionate to the purposes.",order:1,questions:[{id:"lawful_basis",text:"What is the lawful basis for processing under the NDPA 2023?",type:"select",required:true,options:[{value:"consent",label:"Consent (Section 25(1)(a))"},{value:"contract",label:"Contract (Section 25(1)(b))"},{value:"legal_obligation",label:"Legal Obligation (Section 25(1)(c))"},{value:"vital_interests",label:"Vital Interests (Section 25(1)(d))"},{value:"public_task",label:"Public Task (Section 25(1)(e))"},{value:"legitimate_interests",label:"Legitimate Interests (Section 25(1)(f))"}]},{id:"data_minimisation",text:"Is the processing limited to what is necessary for the specified purpose?",type:"radio",required:true,options:[{value:"yes",label:"Yes \u2014 only minimum data is collected",riskLevel:"low"},{value:"partial",label:"Partially \u2014 some additional data may be collected",riskLevel:"medium"},{value:"no",label:"No \u2014 more data is collected than strictly necessary",riskLevel:"high"}]}]},{id:"risk_identification",title:"Risk Identification",description:"Identify and assess risks to data subjects arising from the processing.",order:2,questions:[{id:"sensitive_data",text:"Does the processing involve sensitive personal data (e.g., health, biometric, financial, children's data)?",type:"radio",required:true,options:[{value:"no",label:"No sensitive data",riskLevel:"low"},{value:"yes_protected",label:"Yes, with appropriate safeguards",riskLevel:"medium"},{value:"yes_unprotected",label:"Yes, without adequate safeguards",riskLevel:"high"}]},{id:"scale",text:"What is the scale of processing?",type:"radio",required:true,options:[{value:"small",label:"Small scale (fewer than 1,000 individuals)",riskLevel:"low"},{value:"medium",label:"Medium scale (1,000 to 100,000 individuals)",riskLevel:"medium"},{value:"large",label:"Large scale (over 100,000 individuals)",riskLevel:"high"}]},{id:"cross_border",text:"Will data be transferred outside Nigeria?",type:"radio",required:true,options:[{value:"no",label:"No international transfers",riskLevel:"low"},{value:"adequate",label:"Yes, to countries with adequate protection",riskLevel:"medium"},{value:"inadequate",label:"Yes, to countries without adequate protection",riskLevel:"high"}]}]},{id:"mitigation",title:"Risk Mitigation & Measures",description:"Document the measures taken to address identified risks.",order:3,questions:[{id:"security_measures",text:"What technical and organisational security measures are in place?",guidance:"Include encryption, access controls, pseudonymisation, staff training, etc.",type:"textarea",required:true},{id:"retention_period",text:"What is the data retention period?",guidance:"Specify how long data will be kept and the criteria used to determine this.",type:"text",required:true},{id:"dpo_consulted",text:"Has the Data Protection Officer (DPO) been consulted on this assessment?",type:"radio",required:false,options:[{value:"yes",label:"Yes",riskLevel:"low"},{value:"no",label:"No",riskLevel:"medium"},{value:"na",label:"Not applicable \u2014 no DPO appointed",riskLevel:"medium"}]}]}],z=({sections:d=Y,adapter:t,classNames:p,unstyled:l,onComplete:s=()=>{}})=>{let[c,a]=useState({}),[u,P]=useState(0),f=(i,T)=>{a(B=>b(a$4({},B),{[i]:T}));},e=()=>{u<d.length-1?P(i=>i+1):(t&&t.save(c),s(c));},r=()=>{u>0&&P(i=>i-1);},o=Math.round((u+1)/d.length*100);return jsx(a$5,{sections:d,answers:c,onAnswerChange:f,currentSectionIndex:u,onNextSection:e,onPrevSection:r,progress:o,classNames:p,unstyled:l})};var V=({initialActivities:d=[],adapter:t,classNames:p,unstyled:l})=>{let[s,c]=useState(()=>{if(t){let e=t.load();if(e&&!(e instanceof Promise))return e}return d}),a=e=>{t&&t.save(e);};return jsx(a$6,{activities:s,onAddActivity:e=>{let r=Date.now(),o=b(a$4({},e),{id:`activity-${r}`,createdAt:r,updatedAt:r}),i=[...s,o];c(i),a(i);},onUpdateActivity:(e,r)=>{let o=s.map(i=>i.id===e?b(a$4(a$4({},i),r),{updatedAt:Date.now()}):i);c(o),a(o);},onArchiveActivity:e=>{let r=s.map(o=>o.id===e?b(a$4({},o),{status:"inactive",updatedAt:Date.now()}):o);c(r),a(r);},classNames:p,unstyled:l})};var G=({initialTransfers:d=[],adapter:t,classNames:p,unstyled:l})=>{let[s,c]=useState(()=>{if(t){let e=t.load();if(e&&!(e instanceof Promise))return e}return d}),a=e=>{t&&t.save(e);};return jsx(a$7,{transfers:s,onAddTransfer:e=>{let r=Date.now(),o=b(a$4({},e),{id:`transfer-${r}`,createdAt:r,updatedAt:r}),i=[...s,o];c(i),a(i);},onUpdateTransfer:(e,r)=>{let o=s.map(i=>i.id===e?b(a$4(a$4({},i),r),{updatedAt:Date.now()}):i);c(o),a(o);},onRemoveTransfer:e=>{let r=s.filter(o=>o.id!==e);c(r),a(r);},classNames:p,unstyled:l})};var Z={id:"ndpr-ropa-default",organizationName:"Your Organisation",organizationContact:"",organizationAddress:"",records:[],lastUpdated:Date.now(),version:"1.0"},ee=({initialData:d$1,adapter:t,classNames:p,unstyled:l})=>{let[s,c]=useState(d$1!=null?d$1:Z);useEffect(()=>{if(!t)return;let e=false;return d(null,null,function*(){let o=yield t.load();!e&&o&&c(o);}),()=>{e=true;}},[t]);let a=e=>{t&&t.save(e);};return jsx(a$8,{ropa:s,onAddRecord:e=>{let r=b(a$4({},s),{records:[...s.records,e],lastUpdated:Date.now()});c(r),a(r);},onUpdateRecord:(e,r)=>{let o=b(a$4({},s),{records:s.records.map(i=>i.id===e?b(a$4(a$4({},i),r),{updatedAt:Date.now()}):i),lastUpdated:Date.now()});c(o),a(o);},onArchiveRecord:e=>{let r=b(a$4({},s),{records:s.records.map(o=>o.id===e?b(a$4({},o),{status:"archived",updatedAt:Date.now()}):o),lastUpdated:Date.now()});c(r),a(r);},classNames:p,unstyled:l})};var re=p=>{var l=p,{input:d}=l,t=c(l,["input"]);let s=a$9(d);return jsx(a$a,a$4({report:s},t))};export{U as NDPRBreachReport,re as NDPRComplianceDashboard,I as NDPRConsent,G as NDPRCrossBorder,z as NDPRDPIA,V as NDPRLawfulBasis,E as NDPRPrivacyPolicy,ee as NDPRROPA,k as NDPRSubjectRights};
2
+ export{a as NDPRPrivacyPolicy}from'./chunk-RV2VMWZJ.mjs';import'./chunk-BNHQFZHL.mjs';export{a as NDPRConsent}from'./chunk-LTPSN2SU.mjs';export{a as NDPRSubjectRights}from'./chunk-SJRIOZ4K.mjs';import {a as a$7}from'./chunk-ZIZL37BG.mjs';import {a as a$2}from'./chunk-COD3RMTL.mjs';import {a as a$4}from'./chunk-GTYXVAJX.mjs';import {a as a$5}from'./chunk-EXEXUAF6.mjs';import'./chunk-O6CUBNXK.mjs';import'./chunk-AOHKVFAS.mjs';import {a as a$6}from'./chunk-EFIBHKQE.mjs';import'./chunk-RMQ7OLNY.mjs';import'./chunk-LWIKDDSU.mjs';import'./chunk-7BJXI2HI.mjs';import'./chunk-XP5PL6K7.mjs';import'./chunk-BFAX7JQA.mjs';import'./chunk-YTU4FNM2.mjs';import'./chunk-XJO4DH3L.mjs';import {a as a$1}from'./chunk-ZQZJNKVB.mjs';import {a}from'./chunk-ZHFLBL63.mjs';import'./chunk-EWVK45Z3.mjs';import'./chunk-ITCY2Z66.mjs';import'./chunk-SFGW37LE.mjs';import'./chunk-DBZSN4WP.mjs';import {b,a as a$3,d,c}from'./chunk-ZJYULEER.mjs';import {jsx}from'react/jsx-runtime';import {useState,useEffect}from'react';var L=[{id:"unauthorized_access",name:"Unauthorized Access",description:"Unauthorized access to personal data",defaultSeverity:"high"},{id:"data_loss",name:"Data Loss",description:"Loss of personal data",defaultSeverity:"high"},{id:"data_theft",name:"Data Theft",description:"Theft of personal data",defaultSeverity:"critical"},{id:"system_breach",name:"System Breach",description:"Breach of system containing personal data",defaultSeverity:"critical"},{id:"accidental_disclosure",name:"Accidental Disclosure",description:"Unintended disclosure of personal data",defaultSeverity:"medium"}],I=({categories:c=L,adapter:s,classNames:u,unstyled:p,onSubmit:o=()=>{}})=>jsx(a,{categories:c,onSubmit:d=>{s&&s.save(d),o(d);},classNames:u,unstyled:p});var k=[{id:"project_overview",title:"Project Overview",description:"Provide basic details about the processing activity being assessed.",order:0,questions:[{id:"project_name",text:"What is the name of the project or processing activity?",type:"text",required:true},{id:"project_description",text:"Describe the nature and purpose of the processing.",guidance:"Include what personal data will be collected, why it is needed, and how it will be used.",type:"textarea",required:true},{id:"data_controller",text:"Who is the data controller responsible for this processing?",type:"text",required:true}]},{id:"necessity",title:"Necessity & Proportionality",description:"Assess whether the processing is necessary and proportionate to the purposes.",order:1,questions:[{id:"lawful_basis",text:"What is the lawful basis for processing under the NDPA 2023?",type:"select",required:true,options:[{value:"consent",label:"Consent (Section 25(1)(a))"},{value:"contract",label:"Contract (Section 25(1)(b))"},{value:"legal_obligation",label:"Legal Obligation (Section 25(1)(c))"},{value:"vital_interests",label:"Vital Interests (Section 25(1)(d))"},{value:"public_task",label:"Public Task (Section 25(1)(e))"},{value:"legitimate_interests",label:"Legitimate Interests (Section 25(1)(f))"}]},{id:"data_minimisation",text:"Is the processing limited to what is necessary for the specified purpose?",type:"radio",required:true,options:[{value:"yes",label:"Yes \u2014 only minimum data is collected",riskLevel:"low"},{value:"partial",label:"Partially \u2014 some additional data may be collected",riskLevel:"medium"},{value:"no",label:"No \u2014 more data is collected than strictly necessary",riskLevel:"high"}]}]},{id:"risk_identification",title:"Risk Identification",description:"Identify and assess risks to data subjects arising from the processing.",order:2,questions:[{id:"sensitive_data",text:"Does the processing involve sensitive personal data (e.g., health, biometric, financial, children's data)?",type:"radio",required:true,options:[{value:"no",label:"No sensitive data",riskLevel:"low"},{value:"yes_protected",label:"Yes, with appropriate safeguards",riskLevel:"medium"},{value:"yes_unprotected",label:"Yes, without adequate safeguards",riskLevel:"high"}]},{id:"scale",text:"What is the scale of processing?",type:"radio",required:true,options:[{value:"small",label:"Small scale (fewer than 1,000 individuals)",riskLevel:"low"},{value:"medium",label:"Medium scale (1,000 to 100,000 individuals)",riskLevel:"medium"},{value:"large",label:"Large scale (over 100,000 individuals)",riskLevel:"high"}]},{id:"cross_border",text:"Will data be transferred outside Nigeria?",type:"radio",required:true,options:[{value:"no",label:"No international transfers",riskLevel:"low"},{value:"adequate",label:"Yes, to countries with adequate protection",riskLevel:"medium"},{value:"inadequate",label:"Yes, to countries without adequate protection",riskLevel:"high"}]}]},{id:"mitigation",title:"Risk Mitigation & Measures",description:"Document the measures taken to address identified risks.",order:3,questions:[{id:"security_measures",text:"What technical and organisational security measures are in place?",guidance:"Include encryption, access controls, pseudonymisation, staff training, etc.",type:"textarea",required:true},{id:"retention_period",text:"What is the data retention period?",guidance:"Specify how long data will be kept and the criteria used to determine this.",type:"text",required:true},{id:"dpo_consulted",text:"Has the Data Protection Officer (DPO) been consulted on this assessment?",type:"radio",required:false,options:[{value:"yes",label:"Yes",riskLevel:"low"},{value:"no",label:"No",riskLevel:"medium"},{value:"na",label:"Not applicable \u2014 no DPO appointed",riskLevel:"medium"}]}]}],_=({sections:c=k,adapter:s,classNames:u,unstyled:p,onComplete:o=()=>{}})=>{let[n,d]=useState({}),[m,f]=useState(0),P=(a,C)=>{d(S=>b(a$3({},S),{[a]:C}));},e=()=>{m<c.length-1?f(a=>a+1):(s&&s.save(n),o(n));},t=()=>{m>0&&f(a=>a-1);},r=Math.round((m+1)/c.length*100);return jsx(a$1,{sections:c,answers:n,onAnswerChange:P,currentSectionIndex:m,onNextSection:e,onPrevSection:t,progress:r,classNames:u,unstyled:p})};var F=({initialActivities:c=[],adapter:s,classNames:u,unstyled:p})=>{let[o,n]=useState(()=>{if(s){let e=s.load();if(e&&!(e instanceof Promise))return e}return c}),d=e=>{s&&s.save(e);};return jsx(a$2,{activities:o,onAddActivity:e=>{let t=Date.now(),r=b(a$3({},e),{id:`activity-${t}`,createdAt:t,updatedAt:t}),a=[...o,r];n(a),d(a);},onUpdateActivity:(e,t)=>{let r=o.map(a=>a.id===e?b(a$3(a$3({},a),t),{updatedAt:Date.now()}):a);n(r),d(r);},onArchiveActivity:e=>{let t=o.map(r=>r.id===e?b(a$3({},r),{status:"inactive",updatedAt:Date.now()}):r);n(t),d(t);},classNames:u,unstyled:p})};var W=({initialTransfers:c=[],adapter:s,classNames:u,unstyled:p})=>{let[o,n]=useState(()=>{if(s){let e=s.load();if(e&&!(e instanceof Promise))return e}return c}),d=e=>{s&&s.save(e);};return jsx(a$4,{transfers:o,onAddTransfer:e=>{let t=Date.now(),r=b(a$3({},e),{id:`transfer-${t}`,createdAt:t,updatedAt:t}),a=[...o,r];n(a),d(a);},onUpdateTransfer:(e,t)=>{let r=o.map(a=>a.id===e?b(a$3(a$3({},a),t),{updatedAt:Date.now()}):a);n(r),d(r);},onRemoveTransfer:e=>{let t=o.filter(r=>r.id!==e);n(t),d(t);},classNames:u,unstyled:p})};var j={id:"ndpr-ropa-default",organizationName:"Your Organisation",organizationContact:"",organizationAddress:"",records:[],lastUpdated:Date.now(),version:"1.0"},V=({initialData:c,adapter:s,classNames:u,unstyled:p})=>{let[o,n]=useState(c!=null?c:j);useEffect(()=>{if(!s)return;let e=false;return d(null,null,function*(){let r=yield s.load();!e&&r&&n(r);}),()=>{e=true;}},[s]);let d$1=e=>{s&&s.save(e);};return jsx(a$5,{ropa:o,onAddRecord:e=>{let t=b(a$3({},o),{records:[...o.records,e],lastUpdated:Date.now()});n(t),d$1(t);},onUpdateRecord:(e,t)=>{let r=b(a$3({},o),{records:o.records.map(a=>a.id===e?b(a$3(a$3({},a),t),{updatedAt:Date.now()}):a),lastUpdated:Date.now()});n(r),d$1(r);},onArchiveRecord:e=>{let t=b(a$3({},o),{records:o.records.map(r=>r.id===e?b(a$3({},r),{status:"archived",updatedAt:Date.now()}):r),lastUpdated:Date.now()});n(t),d$1(t);},classNames:u,unstyled:p})};var G=u=>{var p=u,{input:c$1}=p,s=c(p,["input"]);let o=a$6(c$1);return jsx(a$7,a$3({report:o},s))};export{I as NDPRBreachReport,G as NDPRComplianceDashboard,W as NDPRCrossBorder,_ as NDPRDPIA,F as NDPRLawfulBasis,V as NDPRROPA};
package/dist/server.d.mts CHANGED
@@ -3,10 +3,144 @@
3
3
  */
4
4
  export declare type AdequacyStatus = 'adequate' | 'inadequate' | 'pending_review' | 'unknown';
5
5
 
6
- export declare function apiAdapter<T = unknown>(endpoint: string, options?: ApiAdapterOptions): StorageAdapter<T>;
6
+ /**
7
+ * Production-ready API storage adapter.
8
+ *
9
+ * Backward-compatible with the 3.5.x signature — `apiAdapter('/api/x')`
10
+ * still works exactly as before. New options are all opt-in.
11
+ *
12
+ * @example basic
13
+ * const adapter = apiAdapter<ConsentSettings>('/api/consent');
14
+ *
15
+ * @example with credentials and CSRF
16
+ * const adapter = apiAdapter<ConsentSettings>('/api/consent', {
17
+ * credentials: 'include',
18
+ * headers: () => ({
19
+ * 'X-CSRF-Token': document.querySelector<HTMLMetaElement>(
20
+ * 'meta[name="csrf-token"]'
21
+ * )?.content ?? '',
22
+ * }),
23
+ * });
24
+ *
25
+ * @example with retry + telemetry
26
+ * const adapter = apiAdapter<ConsentSettings>('/api/consent', {
27
+ * retry: { attempts: 2, baseDelayMs: 300 },
28
+ * onError: (ctx) => Sentry.captureException(ctx.error, { extra: ctx }),
29
+ * onSuccess: (ctx) => analytics.track('consent_saved', { method: ctx.method }),
30
+ * });
31
+ *
32
+ * @example with response unwrap
33
+ * const adapter = apiAdapter<ConsentSettings>('/api/consent', {
34
+ * // API returns { data: ConsentSettings, ok: true }
35
+ * unwrap: (raw) => (raw as { data: ConsentSettings }).data,
36
+ * });
37
+ */
38
+ export declare function apiAdapter<T = unknown>(endpoint: string, options?: ApiAdapterOptions<T>): StorageAdapter<T>;
39
+
40
+ declare interface ApiAdapterErrorContext<T = unknown> {
41
+ /** Which adapter operation triggered this — `load`, `save`, or `remove`. */
42
+ method: ApiAdapterMethod;
43
+ /** The endpoint URL that failed. */
44
+ endpoint: string;
45
+ /** Underlying error (for network failures / parse errors). */
46
+ error?: unknown;
47
+ /** Response object, if a response was received. */
48
+ response?: Response;
49
+ /** HTTP status code, if available. */
50
+ status?: number;
51
+ /** For `save`, the payload that failed to send. */
52
+ payload?: T;
53
+ /** Which retry attempt this is (0 = first try). Capped at `retry.attempts`. */
54
+ attempt: number;
55
+ }
56
+
57
+ declare type ApiAdapterMethod = 'load' | 'save' | 'remove';
58
+
59
+ declare interface ApiAdapterOptions<T = unknown> {
60
+ /**
61
+ * Extra HTTP headers to send with every request. Useful for `Authorization`,
62
+ * `X-CSRF-Token`, `X-Requested-With`, etc.
63
+ *
64
+ * Can also be a function that returns headers, which lets you read a CSRF
65
+ * token from the DOM/cookie at request time rather than at adapter
66
+ * construction time.
67
+ */
68
+ headers?: Record<string, string> | (() => Record<string, string>);
69
+ /**
70
+ * Forwarded to fetch's `credentials` option. Defaults to `'same-origin'`
71
+ * (the browser default). Set to `'include'` for cross-origin endpoints
72
+ * that need cookies / auth.
73
+ */
74
+ credentials?: RequestCredentials;
75
+ /**
76
+ * HTTP method override for the load operation. Defaults to `'GET'`.
77
+ */
78
+ loadMethod?: 'GET' | 'POST';
79
+ /**
80
+ * HTTP method override for the save operation. Defaults to `'POST'`. Some
81
+ * REST APIs prefer `'PUT'` for upsert semantics.
82
+ */
83
+ saveMethod?: 'POST' | 'PUT' | 'PATCH';
84
+ /**
85
+ * Transform the raw JSON response into the expected `T`. Useful for APIs
86
+ * that wrap responses in `{ data: ... }` or similar envelopes. Called
87
+ * after `res.json()`. If omitted, the parsed JSON is used as-is.
88
+ */
89
+ unwrap?: (raw: unknown) => T | null;
90
+ /**
91
+ * Retry policy for failed requests. Defaults to no retries (preserves the
92
+ * pre-3.6.0 behaviour). When configured, applies to all three operations.
93
+ */
94
+ retry?: ApiAdapterRetryConfig;
95
+ /**
96
+ * Called when a request fails (after all retries exhausted). The adapter
97
+ * still returns a graceful null/void result so the consuming hook
98
+ * doesn't crash — this hook is for telemetry, toasts, or audit logging.
99
+ */
100
+ onError?: (ctx: ApiAdapterErrorContext<T>) => void;
101
+ /**
102
+ * Called when a request succeeds. Useful for cache invalidation,
103
+ * analytics, or syncing other state.
104
+ */
105
+ onSuccess?: (ctx: ApiAdapterSuccessContext<T>) => void;
106
+ /**
107
+ * Per-request fetch options to merge into every request. Use this for
108
+ * things `fetch` itself supports that aren't directly modelled above —
109
+ * `signal`, `mode`, `cache`, `redirect`, etc.
110
+ */
111
+ fetchInit?: Omit<RequestInit, 'method' | 'headers' | 'body' | 'credentials'>;
112
+ }
113
+
114
+ declare interface ApiAdapterRetryConfig {
115
+ /**
116
+ * Number of additional attempts after the initial request. Defaults to 0
117
+ * (no retries). e.g. `attempts: 2` means up to 3 total requests.
118
+ */
119
+ attempts?: number;
120
+ /**
121
+ * Base delay in ms between attempts. Defaults to 250ms. The actual delay
122
+ * uses exponential backoff: `baseDelayMs * 2^attempt`.
123
+ */
124
+ baseDelayMs?: number;
125
+ /**
126
+ * Predicate that decides whether to retry given the failure context. By
127
+ * default we retry on network errors and 5xx responses, but not on 4xx
128
+ * (those are client errors that won't fix themselves).
129
+ */
130
+ shouldRetry?: (ctx: ApiAdapterErrorContext<unknown>) => boolean;
131
+ }
7
132
 
8
- declare interface ApiAdapterOptions {
9
- headers?: Record<string, string>;
133
+ declare interface ApiAdapterSuccessContext<T = unknown> {
134
+ /** Which adapter operation succeeded — `load`, `save`, or `remove`. */
135
+ method: ApiAdapterMethod;
136
+ /** The endpoint URL. */
137
+ endpoint: string;
138
+ /** Response object. */
139
+ response: Response;
140
+ /** For `load` operations, the parsed (and optionally unwrapped) data. */
141
+ data?: T;
142
+ /** For `save` operations, the payload that was sent. */
143
+ payload?: T;
10
144
  }
11
145
 
12
146
  /**