UNPKG

@tantainnovative/ndpr-toolkit

Version:

Nigeria Data Protection Toolkit — enterprise-grade compliance components for the Nigeria Data Protection Act (NDPA) 2023

1,309 lines (1,241 loc) 45.7 kB
import * as React_2 from 'react'; import React__default from 'react'; export declare const AdaptivePolicyWizard: React__default.FC<AdaptivePolicyWizardProps>; declare interface AdaptivePolicyWizardProps { adapter?: StorageAdapter<PolicyDraft>; onComplete?: (policy: PrivacyPolicy) => void; classNames?: Record<string, string>; unstyled?: boolean; /** * Initial template context — seeds the wizard with a sector-specific * pre-fill. Use `templateContextFor('saas' | 'ecommerce' | …)` from * `/server` (or `/core`) to construct it. */ initialContext?: TemplateContext; } /** * Assemble an ordered, NDPA-aligned array of privacy-policy sections from * a {@link TemplateContext}. This is the canonical "compute the policy" * function — it produces structured `PolicySection[]` data that downstream * renderers (`exportHTML`, `exportMarkdown`, `exportPDF`, `exportDOCX`, * `<PolicyPage />`) consume. * * Section composition: * - **Core sections** (always included): Introduction, Data Collection, * Legal Basis, Data Usage, Data Sharing, Data Retention, Data Security, * Data Subject Rights, Contact Information. * - **Conditional sections** (included based on context flags): * - `hasChildrenData` → Children's Data Protection (NDPA §31) * - `hasSensitiveData` → Sensitive / Special-Category Data * - `hasCrossBorderTransfer` → Cross-Border Transfers (NDPA Part VI) * - `hasAutomatedDecisions` → Automated Decision-Making (NDPA §37) * * Section text uses `«TODO: fieldName»` markers (the `UNFILLED_PREFIX` constant) * for any required org-info field that's empty in the context. Pair with * {@link findUnfilledTokens} to surface those before publishing. * * @param context - Organisation info, data categories, processing purposes, * third-party processors, and feature flags. Build a default * context with `createDefaultContext()` then mutate. * @returns An ordered array of {@link PolicySection} objects ready to pass * to `exportHTML(policy)` or `<PolicyPage policy={...} />`. * * @example * ```ts * import { assemblePolicy, createDefaultContext } from '@tantainnovative/ndpr-toolkit/server'; * * const ctx = createDefaultContext(); * ctx.org.name = 'Acme Nigeria Ltd'; * ctx.org.privacyEmail = 'privacy@acme.ng'; * ctx.hasCrossBorderTransfer = true; * * const sections = assemblePolicy(ctx); * // sections is a 10-element array (9 core + 1 cross-border) * ``` */ export declare function assemblePolicy(context: TemplateContext): PolicySection[]; /** A single gap found during NDPA compliance evaluation. */ export declare interface ComplianceGap { /** Machine-readable requirement identifier. */ requirementId: string; /** Human-readable name of the requirement. */ requirement: string; /** Reference to the relevant NDPA section. */ ndpaSection: string; /** How severe the gap is. */ severity: 'critical' | 'important' | 'recommended'; /** Explanation of what is missing. */ message: string; /** Suggested fix type for the UI. */ fixType: 'add_section' | 'add_content' | 'fill_field'; /** Label for the fix action button. */ fixLabel: string; /** Pre-written content the user can insert to close the gap. */ suggestedContent?: string; } /** Result of evaluating a policy against NDPA requirements. */ export declare interface ComplianceResult { /** Points earned. */ score: number; /** Maximum achievable points (115). */ maxScore: number; /** Percentage score (0-100). */ percentage: number; /** Overall compliance rating. */ rating: 'compliant' | 'nearly_compliant' | 'not_compliant'; /** List of identified compliance gaps. */ gaps: ComplianceGap[]; /** List of requirement ids that passed. */ passed: string[]; } /** * Creates a complete business privacy policy template with default * NDPA-compliant sections and variables. * * @returns An object containing the default sections and variables. */ export declare function createBusinessPolicyTemplate(): { sections: PolicySection[]; variables: PolicyVariable[]; }; /** * Creates a default TemplateContext with sensible empty/initial values. * Useful for initialising the wizard state before the user begins editing. */ export declare function createDefaultContext(): TemplateContext; /** A user-defined section added to the policy outside the generated ones. */ export declare interface CustomSection { id: string; title: string; content: string; order: number; required: false; } /** A logical category of personal data the organisation may collect. */ export declare interface DataCategory { /** Machine-readable identifier. */ id: string; /** Human-readable label shown in the wizard. */ label: string; /** Grouping for display and compliance checks. */ group: 'identity' | 'financial' | 'behavioral' | 'sensitive' | 'children'; /** Specific data points within this category. */ dataPoints: string[]; /** Whether this category is currently selected by the user. */ selected: boolean; } /** * Comprehensive set of 16 data categories spanning identity, financial, * behavioral, sensitive, and children groups. Used to populate the wizard * and drive adaptive section generation. */ export declare const DEFAULT_DATA_CATEGORIES: DataCategory[]; /** * Default NDPA-compliant privacy policy sections. * Each section uses {{variable}} placeholders that are resolved at generation time. */ export declare const DEFAULT_POLICY_SECTIONS: PolicySection[]; /** * Default policy variables for NDPA-compliant privacy policies. * These map to the {{variable}} placeholders used in DEFAULT_POLICY_SECTIONS. */ export declare const DEFAULT_POLICY_VARIABLES: PolicyVariable[]; /** Options for DOCX export of the finalised policy. */ declare interface DOCXExportOptions { includeTOC?: boolean; filename?: string; } /** * NDPA policy compliance checker. * * Evaluates a {@link PrivacyPolicy} against 15 requirements drawn from * the Nigeria Data Protection Act (NDPA) 2023, producing a scored * {@link ComplianceResult} with actionable gaps. * * Scoring: * 6 critical @ 10 pts = 60 * 5 important @ 7 pts = 35 * 4 recommended @ 5 pts = 20 * Total max = 115 * * Rating thresholds: * >= 100 → compliant * >= 80 → nearly_compliant * < 80 → not_compliant */ /** * Evaluates a privacy policy against 15 NDPA 2023 requirements and * returns a scored compliance result with actionable gap information. * * @param policy - The privacy policy to evaluate. * @param context - The template context that was used to generate the policy. * @returns A {@link ComplianceResult} with score, rating, gaps, and passed ids. */ export declare function evaluatePolicyCompliance(policy: PrivacyPolicy, context: TemplateContext): ComplianceResult; /** * Export a PrivacyPolicy as a Word (.docx) Blob using the `docx` library * (optional peer dependency). * * Features: * - Title paragraph with large bold text * - Organisation name + version subtitle * - Optional table of contents placeholder heading * - All included policy sections as Heading 1 + body paragraphs / bullet lists * - Running header (org name) and page-number footer on every page * * @throws {Error} if the `docx` package is not installed */ export declare function exportDOCX(policy: PrivacyPolicy, options?: DOCXExportOptions): Promise<Blob>; /** * Export a PrivacyPolicy as a self-contained HTML string. * * The returned string includes: * - An embedded `<style>` block (responsive, dark/light, print-friendly) * - An `<article>` wrapper with semantic markup * - A `<nav>` table of contents with anchor links * - A `<section>` for every included policy section * - A metadata footer (org name, effective date, version, generator credit) * - Optional custom CSS injection via `options.customCSS` */ export declare function exportHTML(policy: PrivacyPolicy, options?: HTMLExportOptions): string; /** * Export a PrivacyPolicy as a clean Markdown string. * * Structure: * ``` * # Policy Title * _Effective: date | Version: X | Org Name_ * * ## Table of Contents * - [Section Title](#anchor) * * ## 1. Section Title * Section content... * ``` */ export declare function exportMarkdown(policy: PrivacyPolicy): string; /** * Export a PrivacyPolicy to a PDF Blob using jspdf (optional peer dependency). * * Requires jspdf >= 4.2.1 (earlier versions carry GHSA-67pg-wm7f-q7fj and * GHSA-cjw8-79x6-5cj4). This function uses only core jsPDF text/vector APIs — * never `addImage`, `addJS`, or `.html()` — so jspdf's optional deps * (canvg, core-js, dompurify, html2canvas) can be omitted (`--omit=optional`). * * Features: * - Optional cover page with title, organisation, date, version and compliance badge * - Optional table of contents page * - One section per heading, content reflowed to fit the page * - Automatic page breaks * - Page header (org name) and footer (page X of Y) on every page * - PDF metadata (title, author, subject, keywords) * * @throws {Error} if the `jspdf` package is not installed */ export declare function exportPDF(policy: PrivacyPolicy, options?: PDFExportOptions): Promise<Blob>; /** * Scan rendered policy text for unfilled placeholder tokens. * * Detects two token forms: * - `«TODO: fieldName»` — sentinel emitted by {@link assemblePolicy} when * a required org-info field is missing from the context. * - `{{fieldName}}` — mustache token that escaped substitution (either * because the variable wasn't declared or its value was empty). * * Returns a deduplicated list of the field names found. An empty array * means the rendered text is fully populated. * * Two recommended uses: * * 1. **CI guard** — assert your canonical org-info fixture renders without * leaving any tokens behind: * ```ts * const html = exportHTML(policy); * expect(findUnfilledTokens(html)).toEqual([]); * ``` * * 2. **Runtime guard** — surface a clear error to compliance officers * before they publish a policy with `{{orgName}}` visible to visitors: * ```ts * const missing = findUnfilledTokens(getPolicyText().fullText); * if (missing.length) throw new Error(`Policy is missing: ${missing.join(', ')}`); * ``` * * @param rendered - The substituted policy text (from `exportHTML`, * `exportMarkdown`, or `usePrivacyPolicy().getPolicyText().fullText`). * @returns Deduplicated array of unfilled field names; `[]` if fully filled. */ export declare function findUnfilledTokens(rendered: string): string[]; /** * Generates policy text by replacing variables in a template with organization-specific values * @param sectionsOrTemplate The policy sections or template string to generate text for * @param organizationInfoOrVariables The organization information or variable map to use for replacement * @returns The generated policy text or an object with the generated text and metadata */ export declare function generatePolicyText(sectionsOrTemplate: PolicySection[] | string, organizationInfoOrVariables: OrganizationInfo | Record<string, string>): string | { fullText: string; sectionTexts: Record<string, string>; missingVariables: string[]; }; /** Options for HTML export of the finalised policy. */ declare interface HTMLExportOptions { includeStyles?: boolean; includePrintCSS?: boolean; customCSS?: string; /** * Theme controlling the embedded design tokens. * * - `'light'` (default): emits the light token palette only. No * `prefers-color-scheme: dark` block is included, so a visitor's OS * dark-mode setting will NOT recolour the policy. This is the right * default for an embedded compliance widget — most consumer host sites * are single-theme and Shadow DOM does not isolate `prefers-color-scheme`. * - `'dark'`: emits the dark token palette as the primary style. * - `'auto'`: emits light tokens plus a `@media (prefers-color-scheme: dark)` * block that swaps to dark on the user's OS preference. Use this when * your host site genuinely follows OS dark mode and you want the policy * to match. * * Pre-3.4.1 the export effectively behaved like `'auto'` unconditionally, * which leaked dark colours into light-only host sites via Shadow DOM. * * @default 'light' */ theme?: 'light' | 'dark' | 'auto'; } /** * Policy engine types for the adaptive privacy policy generator. * These types power the wizard-driven policy builder, compliance checker, * and export functionality — all aligned with the NDPA 2023. */ /** Industry verticals with sector-specific compliance requirements. */ export declare type Industry = 'fintech' | 'healthcare' | 'ecommerce' | 'saas' | 'education' | 'government' | 'other'; /** * Static metadata for every template — useful for picker UIs that need * to list available templates with a one-line description. */ export declare const ORG_POLICY_TEMPLATE_REGISTRY: Record<OrgPolicyTemplateId, { id: OrgPolicyTemplateId; label: string; description: string; /** Best-fit org examples to show in the picker. */ examples: readonly string[]; }>; /** * Represents organization information for a privacy policy */ export declare interface OrganizationInfo { /** Name of the organization */ name: string; /** Website URL of the organization */ website: string; /** Contact email for privacy inquiries */ privacyEmail: string; /** Physical address of the organization */ address?: string; /** Phone number for privacy inquiries */ privacyPhone?: string; /** Name of the Data Protection Officer */ dpoName?: string; /** Email of the Data Protection Officer */ dpoEmail?: string; /** Industry or sector of the organization */ industry?: string; /** NDPC registration number (if registered) */ ndpcRegistrationNumber?: string; } /** * Org-specific privacy-policy templates — pre-filled `TemplateContext` * factories for the most common Nigerian app shapes. * * Each template returns a fully-populated `TemplateContext` with: * - industry set to the matching `Industry` value * - the data categories the sector typically collects (selected: true) * - the processing purposes that match the business model * - sensitive-data / children / cross-border / automated-decisions flags * set to the defaults that org type usually needs (a school will have * children data, a hospital will have sensitive data, etc.) * * Templates are guidance starters. The wizard still walks the user through * every step — they can flip any flag, add/remove categories, or rewrite * any section before the policy is finalised. The legal-notice footer the * toolkit ships everywhere applies to the generated output. * * @example * import { templateContextFor } from '@tantainnovative/ndpr-toolkit/server'; * const ctx = templateContextFor('ecommerce', { orgName: 'Acme NG' }); * const draft = assemblePolicy(ctx); */ /** Identifiers for the bundled org templates. */ export declare type OrgPolicyTemplateId = 'saas' | 'ecommerce' | 'school' | 'healthcare' | 'procurement'; /** Optional overrides applied on top of a template's defaults. */ export declare interface OrgPolicyTemplateOverrides { /** Organisation name (e.g. "Acme Nigeria Ltd"). Default: empty. */ orgName?: string; /** Public website URL. */ website?: string; /** Privacy contact email. */ privacyEmail?: string; /** Postal address. */ address?: string; /** DPO name. Required for DCPMI under NDPA Section 32. */ dpoName?: string; /** DPO email. Required for the NDPC breach-notification contact. */ dpoEmail?: string; } /** Organisation size tiers — affects complexity of generated language. */ export declare type OrgSize = 'startup' | 'midsize' | 'enterprise'; /** Options for PDF export of the finalised policy. */ declare interface PDFExportOptions { includeCoverPage?: boolean; includeTOC?: boolean; includeComplianceBadge?: boolean; logoUrl?: string; filename?: string; } export declare const Policy: { Provider: React_2.FC<PolicyProviderProps>; Generator: React_2.FC<PolicyGeneratorProps>; Preview: React_2.FC<PolicyPreviewProps>; Exporter: React_2.FC<PolicyExporterProps>; }; declare interface PolicyContextValue extends UsePrivacyPolicyReturn { templates: PolicyTemplate[]; } /** Represents an in-progress policy being built in the wizard. */ export declare interface PolicyDraft { /** Unique identifier for the draft. */ id: string; /** The template context driving section generation. */ templateContext: TemplateContext; /** Custom sections added by the user. */ customSections: CustomSection[]; /** Per-section content overrides keyed by section id. */ sectionOverrides: Record<string, string>; /** Ordered list of section ids defining the final order. */ sectionOrder: string[]; /** Current wizard step (0-indexed). */ currentStep: number; /** Timestamp of the last save. */ lastSavedAt: number; /** The draft is always in "draft" status until finalised. */ status: 'draft'; } export declare const PolicyExporter: React__default.FC<PolicyExporterProps>; declare interface PolicyExporterClassNames { /** Root container */ root?: string; /** Header area containing title and description */ header?: string; /** Title element */ title?: string; /** Description element */ description?: string; /** Format selector container */ formatSelector?: string; /** Individual format option */ formatOption?: string; /** Export button */ exportButton?: string; /** Alias for exportButton */ primaryButton?: string; /** NDPA compliance / export tips notice */ complianceNotice?: string; /** Preview / export history area */ preview?: string; } declare interface PolicyExporterProps { /** * The policy content to export */ content: string; /** * The policy title */ title?: string; /** * The organization name to include in the exported policy */ organizationName?: string; /** * The last updated date to include in the exported policy */ lastUpdated?: Date; /** * Callback function called when the export is complete */ onExportComplete?: (format: string, url: string) => void; /** * Title displayed on the exporter * @default "Export Privacy Policy" */ componentTitle?: string; /** * Description text displayed on the exporter * @default "Export your NDPA-compliant privacy policy in various formats." */ description?: string; /** * Custom CSS class for the exporter */ className?: string; /** * Custom CSS class for the buttons */ buttonClassName?: string; /** * Whether to show the export history * @default true */ showExportHistory?: boolean; /** * Whether to include the NDPA compliance notice in the exported policy * @default true */ includeComplianceNotice?: boolean; /** * Whether to include the organization logo in the exported policy * @default false */ includeLogo?: boolean; /** * URL of the organization logo */ logoUrl?: string; /** * Custom CSS styles for the exported policy */ customStyles?: string; /** * Override class names for internal elements */ classNames?: PolicyExporterClassNames; /** * If true, removes all default styles. Use with classNames to apply your own. * @default false */ unstyled?: boolean; } /** * Privacy policy generator component. Implements NDPA Section 27 (provision of * information to the data subject), helping organizations generate compliant * privacy policies that disclose required information. */ export declare const PolicyGenerator: React__default.FC<PolicyGeneratorProps>; declare interface PolicyGeneratorClassNames { /** Root container */ root?: string; /** Header area containing title and description */ header?: string; /** Title element */ title?: string; /** Description element */ description?: string; /** Section list container */ sectionList?: string; /** Individual section item */ sectionItem?: string; /** Variable form container */ form?: string; /** Form input fields */ input?: string; /** Generate button */ generateButton?: string; /** Alias for generateButton */ primaryButton?: string; /** NDPA compliance notice */ complianceNotice?: string; } declare interface PolicyGeneratorProps { /** * List of policy sections * @default DEFAULT_POLICY_SECTIONS */ sections?: PolicySection[]; /** * List of policy variables * @default DEFAULT_POLICY_VARIABLES */ variables?: PolicyVariable[]; /** * Callback function called when the policy is generated */ onGenerate: (policy: { sections: PolicySection[]; variables: PolicyVariable[]; content: string; }) => void; /** * Title displayed on the generator * @default "NDPA Privacy Policy Generator" */ title?: string; /** * Description text displayed on the generator * @default "Generate an NDPA-compliant privacy policy for your organization in accordance with NDPA Section 27." */ description?: string; /** * Custom CSS class for the generator */ className?: string; /** * Custom CSS class for the buttons */ buttonClassName?: string; /** * Text for the generate button * @default "Generate Policy" */ generateButtonText?: string; /** * Whether to show a preview of the generated policy * @default true */ showPreview?: boolean; /** * Whether to allow editing the policy content * @default true */ allowEditing?: boolean; /** * Override class names for internal elements */ classNames?: PolicyGeneratorClassNames; /** * If true, removes all default styles. Use with classNames to apply your own. * @default false */ unstyled?: boolean; } /** * Renders a full privacy policy from a typed `PrivacyPolicy` object. * * ## Choosing a mode * * | mode | renders | SEO | host-CSS isolation | best for | * |------|---------|-----|--------------------|----------| * | `'shadow'` (default) | Inside a Shadow DOM root, opinionated styles included | ❌ markup is invisible to crawlers (lives in shadow) | ✅ structurally impossible to leak | in-app embeds where you want a polished drop-in widget | * | `'inline'` | Directly in the host document body | ✅ crawlable markup | ⚠️ consumer styles the markup themselves | SSR'd `/privacy` pages, public legal pages | * * Inline mode defaults `includeStyles: false` so bare element selectors * (`body`, `article`, `h1`...) don't leak into the host page. The rendered * markup is plain semantic HTML — `<article>`, `<section>`, `<h2>`, `<p>`, * `<ul>`. Pair it with your own typography to make it look right. * * @example **Inline mode + Tailwind `@tailwindcss/typography`** * ```tsx * import { PolicyPage } from '@tantainnovative/ndpr-toolkit'; * * // Wrap with the `prose` class so headings, paragraphs, and lists pick * // up Tailwind's typography defaults. dark:prose-invert handles dark mode. * <article className="prose prose-slate dark:prose-invert max-w-3xl mx-auto"> * <PolicyPage policy={policy} mode="inline" /> * </article> * ``` * * @example **Inline mode with shadcn-ui typography** * ```tsx * <Card> * <CardContent className="prose dark:prose-invert"> * <PolicyPage policy={policy} mode="inline" /> * </CardContent> * </Card> * ``` * * @example **Inline mode with raw CSS** * ```css * .ndpr-policy-page article { font-family: Georgia, serif; line-height: 1.7; } * .ndpr-policy-page h2 { font-size: 1.5rem; margin-top: 2rem; } * .ndpr-policy-page section { margin-bottom: 1.5rem; } * ``` * * @example **Theming the shadow-mode default** * ```tsx * // Brand the policy without leaving shadow mode — pass theme + customCSS. * <PolicyPage * policy={policy} * options={{ * theme: 'auto', // or 'light' (default) / 'dark' * customCSS: ':root { --color-accent: #1d4ed8; --max-width: 64rem; }', * }} * /> * ``` * * HTML is generated internally by `exportHTML` from a typed `PrivacyPolicy` * and never contains untrusted user input. */ export declare const PolicyPage: React__default.FC<PolicyPageProps>; declare type PolicyPageMode = 'shadow' | 'inline'; declare interface PolicyPageProps { policy: PrivacyPolicy; className?: string; /** * Render mode. * * - `'shadow'` (default): mounts the rendered policy inside a Shadow DOM * root, fully isolating the embedded `<style>` block from the host page. * Use this for in-app embeds where you want the rich, opinionated * default styling without polluting global CSS. Client-only. * * - `'inline'`: injects the policy markup directly into the host document. * Defaults to `includeStyles: false` so bare element selectors don't * leak. Pair with your own CSS / design tokens. SSR-safe. */ mode?: PolicyPageMode; /** * Pass-through to {@link exportHTML}. Lets you toggle `includeStyles`, * `includePrintCSS`, or inject `customCSS`. Defaults differ by mode: * shadow mode includes styles; inline mode omits them. */ options?: HTMLExportOptions; } export declare const PolicyPreview: React__default.FC<PolicyPreviewProps>; declare interface PolicyPreviewClassNames { /** Root container */ root?: string; /** Header area containing title and description */ header?: string; /** Title element */ title?: string; /** Description element */ description?: string; /** Content area wrapping the rendered policy */ content?: string; /** Individual rendered section container */ section?: string; /** Section title within rendered content */ sectionTitle?: string; /** Section content within rendered content */ sectionContent?: string; /** NDPA compliance notice */ complianceNotice?: string; } declare interface PolicyPreviewProps { /** * The policy content to preview */ content: string; /** * The policy sections */ sections?: PolicySection[]; /** * The policy variables */ variables?: PolicyVariable[]; /** * Callback function called when the policy is exported */ onExport?: (format: 'pdf' | 'html' | 'markdown' | 'docx') => void; /** * Callback function called when the policy is edited */ onEdit?: () => void; /** * Title displayed on the preview * @default "Privacy Policy Preview" */ title?: string; /** * Description text displayed on the preview * @default "Preview your NDPA-compliant privacy policy before exporting." */ description?: string; /** * Custom CSS class for the preview */ className?: string; /** * Custom CSS class for the buttons */ buttonClassName?: string; /** * Whether to show the export options * @default true */ showExportOptions?: boolean; /** * Whether to show the edit button * @default true */ showEditButton?: boolean; /** * Whether to show the table of contents * @default true */ showTableOfContents?: boolean; /** * Whether to show the policy metadata * @default true */ showMetadata?: boolean; /** * The organization name to display in the policy */ organizationName?: string; /** * The last updated date to display in the policy */ lastUpdated?: Date; /** * Override class names for internal elements */ classNames?: PolicyPreviewClassNames; /** * If true, removes all default styles. Use with classNames to apply your own. * @default false */ unstyled?: boolean; } export declare const PolicyProvider: React__default.FC<PolicyProviderProps>; export declare interface PolicyProviderProps { templates: PolicyTemplate[]; adapter?: StorageAdapter<PrivacyPolicy>; storageKey?: string; useLocalStorage?: boolean; initialPolicy?: PrivacyPolicy; onGenerate?: (policy: PrivacyPolicy) => void; children: React__default.ReactNode; } /** * Privacy policy types aligned with NDPA 2023 * Privacy policies must clearly inform data subjects of their rights under the NDPA */ /** * Represents a section in a privacy policy */ export declare interface PolicySection { /** Unique identifier for the section */ id: string; /** Title of the section */ title: string; /** Description of the section */ description?: string; /** Order of the section in the policy */ order?: number; /** Whether the section is required by NDPA */ required: boolean; /** Template text for the section */ template: string; /** * Default content for the section (legacy field) * @deprecated Use template instead */ defaultContent?: string; /** * Custom content for the section (overrides default content) * @deprecated Use template instead */ customContent?: string; /** Whether the section is included in the policy */ included: boolean; /** Variables that can be used in the section content */ variables?: string[]; } /** * Represents a privacy policy template */ export declare interface PolicyTemplate { /** Unique identifier for the template */ id: string; /** Name of the template */ name: string; /** Description of the template */ description: string; /** Type of organization the template is designed for */ organizationType: 'business' | 'nonprofit' | 'government' | 'educational'; /** Sections included in the template */ sections: PolicySection[]; /** Variables used across the template */ variables: Record<string, { name: string; description: string; required: boolean; defaultValue?: string; }>; /** Version of the template */ version: string; /** Last updated date of the template */ lastUpdated: number; /** * Whether this template is NDPA 2023 compliant */ ndpaCompliant: boolean; } /** * Represents a variable in a privacy policy */ export declare interface PolicyVariable { /** Unique identifier for the variable */ id: string; /** Name of the variable as it appears in the template */ name: string; /** Description of the variable */ description: string; /** Default value for the variable */ defaultValue?: string; /** Current value of the variable */ value: string; /** Type of input for the variable */ inputType: 'text' | 'textarea' | 'email' | 'url' | 'date' | 'select'; /** Options for select inputs */ options?: string[]; /** Whether the variable is required */ required: boolean; } /** * Represents a generated privacy policy */ export declare interface PrivacyPolicy { /** Unique identifier for the policy */ id: string; /** Title of the policy */ title: string; /** Template used to generate the policy */ templateId: string; /** Organization information */ organizationInfo: OrganizationInfo; /** Sections of the policy */ sections: PolicySection[]; /** Values for the variables used in the policy */ variableValues: Record<string, string>; /** Effective date of the policy */ effectiveDate: number; /** Last updated date of the policy */ lastUpdated: number; /** Version of the policy */ version: string; /** * Applicable legal frameworks */ applicableFrameworks?: ('ndpa' | 'ndpr' | 'gdpr' | 'ccpa')[]; } /** Lawful processing purposes recognised under the NDPA. */ export declare type ProcessingPurpose = 'service_delivery' | 'marketing' | 'analytics' | 'research' | 'legal_compliance' | 'fraud_prevention'; export declare interface StorageAdapter<T = unknown> { /** Load persisted data. Called once on hook mount. */ load(): T | null | Promise<T | null>; /** Persist data. Called on every state change. */ save(data: T): void | Promise<void>; /** Clear persisted data. Called on reset. */ remove(): void | Promise<void>; } /** Full context used to generate an adaptive privacy policy. */ export declare interface TemplateContext { /** Organisation details, extended with industry and size. */ org: OrganizationInfo & { industry: Industry; orgSize: OrgSize; country: string; }; /** Data categories the organisation collects. */ dataCategories: DataCategory[]; /** Processing purposes relevant to the organisation. */ purposes: ProcessingPurpose[]; /** Whether the organisation processes children's data. */ hasChildrenData: boolean; /** Whether the organisation processes sensitive/special-category data. */ hasSensitiveData: boolean; /** Whether the organisation processes financial data. */ hasFinancialData: boolean; /** Whether data is transferred outside Nigeria. */ hasCrossBorderTransfer: boolean; /** Whether automated decision-making or profiling is used. */ hasAutomatedDecisions: boolean; /** Third-party processors that receive personal data. */ thirdPartyProcessors: ThirdPartyProcessor[]; } /** * Returns a fresh `TemplateContext` pre-filled for the given org type. * Pass `overrides` to set organisation details (name, DPO, etc.) inline. * * Calling without arguments throws — pass a known template id. * * @example * const ctx = templateContextFor('healthcare', { * orgName: 'Lagos Heart Centre', * dpoEmail: 'dpo@lhc.ng', * }); */ declare function templateContextFor(id: OrgPolicyTemplateId, overrides?: OrgPolicyTemplateOverrides): TemplateContext; export { templateContextFor as createOrgTemplate } export { templateContextFor } /** A third-party entity that processes data on behalf of the organisation. */ export declare interface ThirdPartyProcessor { /** Name of the third party. */ name: string; /** Purpose of sharing data with this processor. */ purpose: string; /** Country where the processor is located. */ country: string; } /** * Multi-step privacy-policy authoring hook that adapts the generated draft * to the supplied template context (industry, processing purposes, data * categories, processors). Auto-persists a draft via the supplied adapter * and surfaces a live compliance score against the configured rule set. * * @example * ```tsx * import { useAdaptivePolicyWizard } from '@tantainnovative/ndpr-toolkit/hooks'; * * function PolicyWizard() { * const { currentStep, nextStep, policy, complianceScore } = useAdaptivePolicyWizard(); * return ( * <div> * <p>Step {currentStep} — compliance: {complianceScore}%</p> * <button onClick={nextStep}>Next</button> * {policy && <pre>{policy.title}</pre>} * </div> * ); * } * ``` */ export declare function useAdaptivePolicyWizard(options?: UseAdaptivePolicyWizardOptions): UseAdaptivePolicyWizardReturn; export declare interface UseAdaptivePolicyWizardOptions { adapter?: StorageAdapter<PolicyDraft>; onComplete?: (policy: PrivacyPolicy) => void; onComplianceChange?: (score: number, gaps: ComplianceGap[]) => void; /** * Initial template context. Use an org-template factory like * `templateContextFor('healthcare')` to start the wizard with a sector- * specific pre-fill (lawful basis, data categories, sensitive-data flag, * cross-border default). Defaults to `createDefaultContext()` if omitted. * * If an adapter loads a saved draft, the draft's context wins — the * `initialContext` only seeds the very first session. */ initialContext?: TemplateContext; } export declare interface UseAdaptivePolicyWizardReturn { currentStep: number; goToStep: (step: number) => void; nextStep: () => void; prevStep: () => void; canProceed: boolean; context: TemplateContext; updateContext: (updates: Partial<TemplateContext>) => void; updateOrg: (updates: Partial<TemplateContext['org']>) => void; toggleDataCategory: (categoryId: string) => void; togglePurpose: (purpose: string) => void; addProcessor: (processor: { name: string; purpose: string; country: string; }) => void; removeProcessor: (index: number) => void; policy: PrivacyPolicy | null; sections: PolicySection[]; customSections: CustomSection[]; addCustomSection: (section: Omit<CustomSection, 'id' | 'required'>) => void; updateCustomSection: (id: string, updates: Partial<CustomSection>) => void; removeCustomSection: (id: string) => void; reorderSections: (sectionId: string, direction: 'up' | 'down') => void; editSectionContent: (sectionId: string, content: string) => void; sectionOverrides: Record<string, string>; complianceScore: number; complianceResult: ComplianceResult; complianceGaps: ComplianceGap[]; applyFix: (gapId: string) => void; handleExportPDF: (options?: PDFExportOptions) => Promise<Blob>; handleExportDOCX: (options?: DOCXExportOptions) => Promise<Blob>; handleExportHTML: (options?: HTMLExportOptions) => string; handleExportMarkdown: () => string; isDraftSaved: boolean; lastSavedAt: number | null; saveDraft: () => Promise<void>; discardDraft: () => void; isLoading: boolean; } /** * Convenience wrapper around `usePrivacyPolicy`. With `orgInfo` provided * and `autoGenerate` enabled (default), `policy` is non-null on the first * post-load render — no manual `selectTemplate` / `generatePolicy` chaining * required. * * @example * ```tsx * const { policy } = useDefaultPrivacyPolicy({ * orgInfo: { name: 'Acme Ltd', email: 'privacy@acme.ng' } * }); * return policy ? <PolicyPage policy={policy} /> : <Spinner />; * ``` */ export declare function useDefaultPrivacyPolicy(options?: UseDefaultPrivacyPolicyOptions): UsePrivacyPolicyReturn; declare interface UseDefaultPrivacyPolicyOptions { /** * Organisation information to pre-fill into the policy. When provided and * `autoGenerate` is true (the default), the hook will auto-select the * default template and generate a renderable policy on first commit, so * `policy` is non-null on the first useful render. */ orgInfo?: { /** Organisation name (maps to `organizationInfo.name` and `orgName` variable) */ name?: string; /** Privacy contact email (maps to `privacyEmail`) */ email?: string; /** Organisation website URL */ website?: string; /** Physical address */ address?: string; /** Industry / sector descriptor */ industry?: string; /** Data Protection Officer name */ dpoName?: string; /** DPO email address */ dpoEmail?: string; }; /** * Whether the hook should auto-select the default template and generate * the policy as soon as it's mounted with `orgInfo`. Set to false to * retain manual control via `selectTemplate` / `generatePolicy`. * @default true */ autoGenerate?: boolean; /** * Storage key for policy data. * @default "ndpr_privacy_policy" */ storageKey?: string; /** * Whether to persist policy data in storage. When `false`, the hook * uses an in-memory no-op adapter and nothing survives a page reload. * @default true */ persist?: boolean; /** * @deprecated Renamed to `persist` in v3.5.0 — `useLocalStorage` is * still accepted for backward compatibility and will be removed in * v4.0. Use `persist` (or pass an explicit `adapter`) instead. * @default true */ useLocalStorage?: boolean; /** * Pluggable storage adapter. When provided, takes precedence over * storageKey/persist/useLocalStorage. */ adapter?: StorageAdapter<PrivacyPolicy>; } export declare function usePolicyCompound(): PolicyContextValue; /** * Hook for generating NDPA-compliant privacy policies. * * @example * ```tsx * import { usePrivacyPolicy } from '@tantainnovative/ndpr-toolkit/hooks'; * * function PolicyBuilder({ templates }) { * const { policy, selectTemplate, generatePolicy } = usePrivacyPolicy({ templates }); * return ( * <div> * <button onClick={() => selectTemplate(templates[0].id)}>Select default</button> * <button onClick={generatePolicy}>Generate</button> * {policy && <pre>{policy.title}</pre>} * </div> * ); * } * ``` */ export declare function usePrivacyPolicy({ templates, initialPolicy, adapter, storageKey, persist, useLocalStorage, onGenerate, }: UsePrivacyPolicyOptions): UsePrivacyPolicyReturn; declare interface UsePrivacyPolicyOptions { /** * Available policy templates */ templates: PolicyTemplate[]; /** * Initial policy data (if editing an existing policy) */ initialPolicy?: PrivacyPolicy; /** * Pluggable storage adapter. When provided, takes precedence over storageKey/useLocalStorage. */ adapter?: StorageAdapter<PrivacyPolicy>; /** * Storage key for policy data * @default "ndpr_privacy_policy" * @deprecated Use adapter instead */ storageKey?: string; /** * Whether to persist policy data in storage. When `false`, the hook * uses an in-memory no-op adapter and nothing survives a page reload. * Prefer `adapter` for richer control (custom backends, async APIs). * * @default true */ persist?: boolean; /** * @deprecated Renamed to `persist` in v3.5.0 — `useLocalStorage` is * still accepted for backward compatibility and will be removed in * v4.0. Use `persist` (or pass an explicit `adapter`) instead. * @default true */ useLocalStorage?: boolean; /** * Callback function called when a policy is generated */ onGenerate?: (policy: PrivacyPolicy) => void; } declare interface UsePrivacyPolicyReturn { /** * Current policy data */ policy: PrivacyPolicy | null; /** * Selected template */ selectedTemplate: PolicyTemplate | null; /** * Organization information */ organizationInfo: OrganizationInfo; /** * Select a template */ selectTemplate: (templateId: string) => boolean; /** * Update organization information */ updateOrganizationInfo: (updates: Partial<OrganizationInfo>) => void; /** * Toggle whether a section is included in the policy */ toggleSection: (sectionId: string, included: boolean) => void; /** * Update section content */ updateSectionContent: (sectionId: string, content: string) => void; /** * Update variable values */ updateVariableValue: (variable: string, value: string) => void; /** * Generate the policy */ generatePolicy: () => PrivacyPolicy | null; /** * Get the generated policy text */ getPolicyText: () => { fullText: string; sectionTexts: Record<string, string>; missingVariables: string[]; }; /** * Reset the policy */ resetPolicy: () => void; /** * Check if the policy is valid */ isValid: () => { valid: boolean; errors: string[]; }; /** * Whether the adapter is still loading data (relevant for async adapters) */ isLoading: boolean; } export { }