@tantainnovative/ndpr-toolkit 5.0.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,33 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
4
4
 
5
+ ## [5.1.0](https://github.com/mr-tanta/ndpr-toolkit/compare/v5.0.1...v5.1.0) (2026-05-28)
6
+
7
+ Security hygiene for the optional PDF-export peer. No change to the toolkit's own code — peer range + docs only.
8
+
9
+ ### Changed
10
+
11
+ - **`jspdf` peer range widened: `^3.0.3` → `^3.0.3 || ^4.2.1`.** jspdf ≤ 4.2.0 carries three advisories — `GHSA-67pg-wm7f-q7fj` (High, CVSS 8.7: `addImage` GIF out-of-memory DoS), `GHSA-cjw8-79x6-5cj4` (Medium: `addJS` shared-state cross-user data leakage in concurrent server-side use), and a Critical path-traversal/LFI item. jspdf **4.2.1** clears all of them (`npm audit`: 0 vulnerabilities). The old `^3.0.3` peer pinned consumers to vulnerable 3.x; the widened range lets them install the patched 4.2.1+.
12
+
13
+ The toolkit's `exportPDF` only uses core jsPDF text/vector primitives — it never calls `addImage`, `addJS`, or `.html()` — so the toolkit's own PDF path was never a sink for these CVEs. The bump is for consumers who install jspdf and want a clean audit. jspdf stays an **optional** peer (dynamic `import('jspdf')`); consumers who don't export PDFs never install it.
14
+
15
+ ### Docs
16
+
17
+ - README + `exportPDF` JSDoc now note that PDF export needs **jspdf ≥ 4.2.1**, and that installing it with `--omit=optional` (npm) / `--no-optional` (pnpm) drops jspdf's optional deps (`canvg`, `core-js`, `dompurify`, `html2canvas`) for a dependency-free PDF surface — the toolkit uses none of them.
18
+
19
+ ### Verification
20
+
21
+ - `npm audit` against `jspdf@4.2.1` — 0 vulnerabilities
22
+ - `pnpm jest --no-coverage`, `pnpm verify:tarball`, `npx tsc --noEmit -p tsconfig.json` — all green
23
+
24
+ ## [5.0.1](https://github.com/mr-tanta/ndpr-toolkit/compare/v5.0.0...v5.0.1) (2026-05-28)
25
+
26
+ Docs-only patch. No runtime code change.
27
+
28
+ - README refresh for 5.0: structured-result validator examples (route-handler + client branching), new Internationalization section listing all seven shipped locales (en, yo, ig, ha, pcm, ar, fr) with RTL guidance, `/server` and `/core` import examples switched to `validateConsentStructured`, `cookieAdapter` default documented as 180 days with NDPA Section 26 rationale, and every `raw.githubusercontent.com/.../vN.N.N/...` image URL pinned to the v5.0.0 tag.
29
+
30
+ The npm page now matches the v5 surface. No code, types, or exports changed — `^5.0.0` consumers do not need to upgrade unless they want the new README on their npm page.
31
+
5
32
  ## [5.0.0](https://github.com/mr-tanta/ndpr-toolkit/compare/v4.1.0...v5.0.0) (2026-05-27)
6
33
 
7
34
  Closes the deprecation window opened by 4.1.0. Every removal here was already deprecated and dev-warned in 4.1, so if your 4.1.x dev console was clean, your 5.0 upgrade is a one-line bump. Full migration table in [`/docs/guides/migrating-4-1-to-5-0`](https://ndprtoolkit.com.ng/docs/guides/migrating-4-1-to-5-0).
package/README.md CHANGED
@@ -9,19 +9,19 @@
9
9
  [![CI](https://github.com/mr-tanta/ndpr-toolkit/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mr-tanta/ndpr-toolkit/actions/workflows/ci.yml)
10
10
  [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@tantainnovative/ndpr-toolkit)](https://bundlephobia.com/package/@tantainnovative/ndpr-toolkit)
11
11
 
12
- v3 ships **zero-config presets**, **pluggable storage adapters**, **compound components**, and a **compliance score engine** — eight production-ready modules covering consent, data subject rights, DPIA, breach notification, privacy policies, lawful basis, cross-border transfers, and ROPA.
12
+ v5 ships **zero-config presets**, **pluggable storage adapters**, **compound components**, **structured-error validators**, a **compliance score engine**, and **seven shipped locales** (en, yo, ig, ha, pcm, ar, fr) — eight production-ready modules covering consent, data subject rights, DPIA, breach notification, privacy policies, lawful basis, cross-border transfers, and ROPA.
13
13
 
14
- **[Documentation](https://ndprtoolkit.com.ng)** | **[Live Demos](https://ndprtoolkit.com.ng/ndpr-demos)** | **[npm](https://www.npmjs.com/package/@tantainnovative/ndpr-toolkit)** | **[Blog](https://ndprtoolkit.com.ng/blog)** | **[v3.11.0 Release](https://github.com/mr-tanta/ndpr-toolkit/releases/tag/v3.11.0)**
14
+ **[Documentation](https://ndprtoolkit.com.ng)** | **[Live Demos](https://ndprtoolkit.com.ng/ndpr-demos)** | **[npm](https://www.npmjs.com/package/@tantainnovative/ndpr-toolkit)** | **[Blog](https://ndprtoolkit.com.ng/blog)** | **[v5.0.0 Release](https://github.com/mr-tanta/ndpr-toolkit/releases/tag/v5.0.0)**
15
15
 
16
16
  [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/nextjs-app)
17
17
  [![Open in CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/github/mr-tanta/ndpr-toolkit/main/examples/nextjs-app)
18
18
 
19
- > **What's new in 3.11.0:** Every component's `Props` interface is now re-exported from the root (consumers can finally wrap toolkit components without copying types). Adapter ecosystem types (`ApiAdapterErrorContext`, `StorageAdapter<T>`, …) and DSR validator types reachable from `/server` + root. 9 new component docs pages cover `NDPRThemeProvider`, `NDPRProvider`, `NDPRDashboard`, `AdaptivePolicyWizard`, `PolicyPage`, the 3 Lite manager variants, and `LegalNotice`.
19
+ > **What's new in 5.0:** Structured-result validators are now the only shape `validateConsentStructured`, `validateDsrSubmissionStructured`, `formatDSRRequestStructured`, etc. return `{ field, code, message }[]` so consumers can switch on stable, locale-independent codes (`email_invalid_format`, `consent_stale`, …) instead of regex-matching English strings. Uniform `onAdd` / `onUpdate` / `onArchive` callbacks across `LawfulBasisTracker`, `CrossBorderTransferManager`, `ROPAManager`, and `useROPA`. `NDPRDPIA.onResult(result)` replaces `onComplete(answers)` — the callback now receives the full computed `DPIAResult` (risk level, can-proceed verdict, recommendations). Upgrading from 4.1? See the [4.1 → 5.0 migration guide](https://ndprtoolkit.com.ng/docs/guides/migrating-4-1-to-5-0).
20
20
  >
21
- > **3.10.x highlights:** Typed theming via `<NDPRThemeProvider>`, a `/headless` subpath alias of `/hooks`, the production-grade DSR backend reference at `examples/dsr-backend-reference/`, plus the `verify:tarball` CI gate that catches broken exports at PR time. Upgrading from 3.7.x? See the [3.7 → 3.10 upgrade guide](https://ndprtoolkit.com.ng/docs/guides/upgrading-3-7-to-3-10). Full history in the [CHANGELOG](https://github.com/mr-tanta/ndpr-toolkit/blob/main/CHANGELOG.md).
21
+ > **Recent highlights:** Arabic + French locales with RTL-correct CSS (4.1.0). React 17 dropped from peers; `^18 || ^19` is the honest range (4.0.0). 17 components wired through `useNDPRLocale()` for full Yoruba / Igbo / Hausa / Pidgin coverage (3.13.0). Typed theming via `<NDPRThemeProvider>`, `verify:tarball` CI gate that catches broken exports at PR time (3.10.x). Full history in the [CHANGELOG](https://github.com/mr-tanta/ndpr-toolkit/blob/main/CHANGELOG.md).
22
22
 
23
23
  <p align="center">
24
- <img src="https://raw.githubusercontent.com/mr-tanta/ndpr-toolkit/v3.11.0/public/screenshots/hero.png" alt="NDPA Toolkit — NDPA Compliance Made Beautiful" width="800" />
24
+ <img src="https://raw.githubusercontent.com/mr-tanta/ndpr-toolkit/v5.0.0/public/screenshots/hero.png" alt="NDPA Toolkit — NDPA Compliance Made Beautiful" width="800" />
25
25
  </p>
26
26
 
27
27
  ---
@@ -71,7 +71,7 @@ import { cookieAdapter, apiAdapter, composeAdapters, localStorageAdapter } from
71
71
  The full SSR pattern (cookie read server-side → banner hydrates already-resolved, no flash) is in the [Server-Side Storage guide](https://ndprtoolkit.com.ng/docs/guides/server-side-storage).
72
72
 
73
73
  <p align="center">
74
- <img src="https://raw.githubusercontent.com/mr-tanta/ndpr-toolkit/v3.11.0/public/screenshots/consent-demo.png" alt="Consent Management Demo — interactive consent banner with state inspector" width="800" />
74
+ <img src="https://raw.githubusercontent.com/mr-tanta/ndpr-toolkit/v5.0.0/public/screenshots/consent-demo.png" alt="Consent Management Demo — interactive consent banner with state inspector" width="800" />
75
75
  <br />
76
76
  <em>Interactive consent demo with configurable position, theme, storage, and real-time state inspector</em>
77
77
  </p>
@@ -278,7 +278,8 @@ The recommended entry for backend and serverless contexts. Pure validators, gene
278
278
 
279
279
  ```ts
280
280
  import {
281
- validateConsent,
281
+ validateConsentStructured,
282
+ validateDsrSubmissionStructured,
282
283
  generatePolicyText,
283
284
  exportHTML,
284
285
  getComplianceScore,
@@ -292,7 +293,7 @@ Build-output guard tests assert this entry never carries a `"use client"` direct
292
293
  Adds the `NDPRProvider` React Context on top of `/server`'s pure surface. Use when you want types and validators alongside the provider in the same import.
293
294
 
294
295
  ```ts
295
- import { NDPRProvider, validateConsent, getComplianceScore } from '@tantainnovative/ndpr-toolkit/core';
296
+ import { NDPRProvider, validateConsentStructured, getComplianceScore } from '@tantainnovative/ndpr-toolkit/core';
296
297
  ```
297
298
 
298
299
  ### Adapters — pluggable storage
@@ -357,9 +358,44 @@ import { composeAdapters, apiAdapter, localStorageAdapter } from '@tantainnovati
357
358
 
358
359
  **Cookie (server-readable, for SSR consent gating):**
359
360
  ```tsx
360
- <NDPRConsent adapter={cookieAdapter('ndpr_consent', { expires: 365 })} />
361
+ <NDPRConsent adapter={cookieAdapter('ndpr_consent', { expires: 180 })} />
361
362
  ```
362
363
 
364
+ `expires` defaults to **180 days** (since 3.10.5). NDPA Section 26 doesn't pin a number, but 6 months is the common practice for non-essential cookies and matches what regulators have published elsewhere — long enough to avoid daily re-prompting, short enough that consent stays meaningful.
365
+
366
+ ---
367
+
368
+ ## Structured-Result Validators
369
+
370
+ Every validator returns a typed `{ field, code, message }[]` so client and server code can branch on stable, locale-independent codes — not regex-matched English strings.
371
+
372
+ **Next.js Route Handler:**
373
+ ```ts
374
+ import { validateDsrSubmissionStructured } from '@tantainnovative/ndpr-toolkit/server';
375
+
376
+ export async function POST(req: Request) {
377
+ const { valid, errors, data } = validateDsrSubmissionStructured(await req.json());
378
+ if (!valid) {
379
+ return Response.json({ errors }, { status: 422 });
380
+ // errors: Array<{ field: 'dataSubject.email', code: 'email_invalid_format', message: '...' }>
381
+ }
382
+ // `data` is the narrowed `DsrSubmissionPayload`
383
+ await dsrStore.create(data);
384
+ return Response.json({ ok: true }, { status: 201 });
385
+ }
386
+ ```
387
+
388
+ **Client-side branching:**
389
+ ```ts
390
+ import { validateConsentStructured } from '@tantainnovative/ndpr-toolkit';
391
+
392
+ const { valid, errors } = validateConsentStructured(settings);
393
+ const stale = errors.find((e) => e.code === 'consent_stale');
394
+ if (stale) showRefreshBanner();
395
+ ```
396
+
397
+ Each validator's emitted `code` values are documented in its JSDoc (and listed in the [CHANGELOG 5.0 entry](https://github.com/mr-tanta/ndpr-toolkit/blob/main/CHANGELOG.md#500-2026-05-27)). The legacy string-returning shapes (`validateConsent`, `validateDsrSubmission`, `formatDSRRequest`, `validateConsentOptions`) were removed in 5.0 — see the [4.1 → 5.0 migration guide](https://ndprtoolkit.com.ng/docs/guides/migrating-4-1-to-5-0) if you're upgrading.
398
+
363
399
  ---
364
400
 
365
401
  ## Compliance Score
@@ -448,13 +484,13 @@ Every module has an interactive demo. No signup, no setup — try them instantly
448
484
 
449
485
  <p align="center">
450
486
  <a href="https://ndprtoolkit.com.ng/ndpr-demos">
451
- <img src="https://raw.githubusercontent.com/mr-tanta/ndpr-toolkit/v3.11.0/public/screenshots/demos-overview.png" alt="8 interactive live demos — zero setup required" width="800" />
487
+ <img src="https://raw.githubusercontent.com/mr-tanta/ndpr-toolkit/v5.0.0/public/screenshots/demos-overview.png" alt="8 interactive live demos — zero setup required" width="800" />
452
488
  </a>
453
489
  </p>
454
490
 
455
491
  <p align="center">
456
- <img src="https://raw.githubusercontent.com/mr-tanta/ndpr-toolkit/v3.11.0/public/screenshots/dsr-demo.png" alt="Data Subject Rights — 8 rights with request tracking" width="400" />
457
- <img src="https://raw.githubusercontent.com/mr-tanta/ndpr-toolkit/v3.11.0/public/screenshots/breach-demo.png" alt="Breach Notification — 72-hour countdown with step-by-step workflow" width="400" />
492
+ <img src="https://raw.githubusercontent.com/mr-tanta/ndpr-toolkit/v5.0.0/public/screenshots/dsr-demo.png" alt="Data Subject Rights — 8 rights with request tracking" width="400" />
493
+ <img src="https://raw.githubusercontent.com/mr-tanta/ndpr-toolkit/v5.0.0/public/screenshots/breach-demo.png" alt="Breach Notification — 72-hour countdown with step-by-step workflow" width="400" />
458
494
  </p>
459
495
 
460
496
  <p align="center">
@@ -491,6 +527,34 @@ Cookie-bridged consent that hydrates without a flash. Each scaffold reads the `n
491
527
 
492
528
  ---
493
529
 
530
+ ## Internationalization
531
+
532
+ Wrap your app in `<NDPRProvider locale={...}>` and every shipped component picks up the translation:
533
+
534
+ ```tsx
535
+ import { NDPRProvider, arabicLocale, frenchLocale } from '@tantainnovative/ndpr-toolkit/core';
536
+
537
+ <NDPRProvider locale={arabicLocale}>
538
+ <App />
539
+ </NDPRProvider>
540
+ ```
541
+
542
+ Seven locales ship out of the box:
543
+
544
+ | Locale | Export | Notes |
545
+ |---|---|---|
546
+ | English | `defaultLocale` | Default |
547
+ | Yoruba | `yorubaLocale` | |
548
+ | Igbo | `igboLocale` | |
549
+ | Hausa | `hausaLocale` | |
550
+ | Nigerian Pidgin | `pidginLocale` | |
551
+ | Arabic | `arabicLocale` | Modern Standard; RTL-aware. Set `dir="rtl"` on a parent and `styles.css` mirrors correctly (logical properties as of 4.1). |
552
+ | French | `frenchLocale` | Francophone West African register; uses GDPR-equivalent French terms where they carry meaning. |
553
+
554
+ Override individual strings via `mergeLocale(base, partial)`. Component prop overrides (`title`, `description`, etc.) still win over the provider locale — the resolution order is **prop → provider locale → English default**.
555
+
556
+ ---
557
+
494
558
  ## All 8 Modules
495
559
 
496
560
  | Module | Import path | NDPA reference | Key exports |
@@ -590,7 +654,7 @@ Each component exports its `ClassNames` TypeScript interface for autocomplete. F
590
654
  | `/dsr` | DSR components + hook | `react` | No |
591
655
  | `/dpia` | DPIA components + hook | `react` | No |
592
656
  | `/breach` | Breach components + hook | `react` | No |
593
- | `/policy` | Policy components + hook | `react`, `jspdf`, `docx` (optional) | No |
657
+ | `/policy` | Policy components + hook | `react`, `jspdf` ≥ 4.2.1, `docx` (both optional) | No |
594
658
  | `/lawful-basis` | Lawful basis component + hook | `react` | No |
595
659
  | `/lawful-basis/lite` | Read-only `LawfulBasisTrackerLite` — ~65% smaller than `/lawful-basis` | `react` | No |
596
660
  | `/cross-border` | Cross-border component + hook | `react` | No |
@@ -602,6 +666,17 @@ Each component exports its `ClassNames` TypeScript interface for autocomplete. F
602
666
 
603
667
  [^core]: `/core` re-exports the React `NDPRProvider` for backward compatibility. For strictly server-side imports use `/server` — it carries the same pure validators with no React surface.
604
668
 
669
+ ### PDF / DOCX export peers
670
+
671
+ `PolicyExporter` (and `exportPDF` / `exportDOCX` from `/policy`) load `jspdf` / `docx` via dynamic `import()` only when you actually export — they're optional peers, so consumers who don't export documents never install them. If you do export to PDF:
672
+
673
+ ```bash
674
+ npm install jspdf@^4.2.1 --omit=optional # npm
675
+ pnpm add jspdf@^4.2.1 --no-optional # pnpm
676
+ ```
677
+
678
+ Use **jspdf ≥ 4.2.1** — earlier versions (≤ 4.2.0) carry advisories `GHSA-67pg-wm7f-q7fj` and `GHSA-cjw8-79x6-5cj4`, fixed in 4.2.1. The `--omit=optional` / `--no-optional` flag drops jspdf's own optional deps (`canvg`, `core-js`, `dompurify`, `html2canvas`); the toolkit's PDF export uses only core jsPDF text/vector APIs, so it works without them and you get a leaner, dependency-flag-free install.
679
+
605
680
  ### Bundle size guidance
606
681
 
607
682
  The toolkit is published with `sideEffects: ["*.css"]`, so a modern bundler (Vite, Next.js / Webpack, esbuild, Bun) will tree-shake unused exports. A few practical rules to keep your bundle small:
package/dist/policy.d.mts CHANGED
@@ -236,6 +236,11 @@ export declare function exportMarkdown(policy: PrivacyPolicy): string;
236
236
  /**
237
237
  * Export a PrivacyPolicy to a PDF Blob using jspdf (optional peer dependency).
238
238
  *
239
+ * Requires jspdf >= 4.2.1 (earlier versions carry GHSA-67pg-wm7f-q7fj and
240
+ * GHSA-cjw8-79x6-5cj4). This function uses only core jsPDF text/vector APIs —
241
+ * never `addImage`, `addJS`, or `.html()` — so jspdf's optional deps
242
+ * (canvg, core-js, dompurify, html2canvas) can be omitted (`--omit=optional`).
243
+ *
239
244
  * Features:
240
245
  * - Optional cover page with title, organisation, date, version and compliance badge
241
246
  * - Optional table of contents page
package/dist/policy.d.ts CHANGED
@@ -236,6 +236,11 @@ export declare function exportMarkdown(policy: PrivacyPolicy): string;
236
236
  /**
237
237
  * Export a PrivacyPolicy to a PDF Blob using jspdf (optional peer dependency).
238
238
  *
239
+ * Requires jspdf >= 4.2.1 (earlier versions carry GHSA-67pg-wm7f-q7fj and
240
+ * GHSA-cjw8-79x6-5cj4). This function uses only core jsPDF text/vector APIs —
241
+ * never `addImage`, `addJS`, or `.html()` — so jspdf's optional deps
242
+ * (canvg, core-js, dompurify, html2canvas) can be omitted (`--omit=optional`).
243
+ *
239
244
  * Features:
240
245
  * - Optional cover page with title, organisation, date, version and compliance badge
241
246
  * - Optional table of contents page
package/dist/server.d.mts CHANGED
@@ -1134,6 +1134,11 @@ export declare function exportMarkdown(policy: PrivacyPolicy): string;
1134
1134
  /**
1135
1135
  * Export a PrivacyPolicy to a PDF Blob using jspdf (optional peer dependency).
1136
1136
  *
1137
+ * Requires jspdf >= 4.2.1 (earlier versions carry GHSA-67pg-wm7f-q7fj and
1138
+ * GHSA-cjw8-79x6-5cj4). This function uses only core jsPDF text/vector APIs —
1139
+ * never `addImage`, `addJS`, or `.html()` — so jspdf's optional deps
1140
+ * (canvg, core-js, dompurify, html2canvas) can be omitted (`--omit=optional`).
1141
+ *
1137
1142
  * Features:
1138
1143
  * - Optional cover page with title, organisation, date, version and compliance badge
1139
1144
  * - Optional table of contents page
package/dist/server.d.ts CHANGED
@@ -1134,6 +1134,11 @@ export declare function exportMarkdown(policy: PrivacyPolicy): string;
1134
1134
  /**
1135
1135
  * Export a PrivacyPolicy to a PDF Blob using jspdf (optional peer dependency).
1136
1136
  *
1137
+ * Requires jspdf >= 4.2.1 (earlier versions carry GHSA-67pg-wm7f-q7fj and
1138
+ * GHSA-cjw8-79x6-5cj4). This function uses only core jsPDF text/vector APIs —
1139
+ * never `addImage`, `addJS`, or `.html()` — so jspdf's optional deps
1140
+ * (canvg, core-js, dompurify, html2canvas) can be omitted (`--omit=optional`).
1141
+ *
1137
1142
  * Features:
1138
1143
  * - Optional cover page with title, organisation, date, version and compliance badge
1139
1144
  * - Optional table of contents page
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tantainnovative/ndpr-toolkit",
3
- "version": "5.0.0",
3
+ "version": "5.1.0",
4
4
  "private": false,
5
5
  "description": "Nigeria Data Protection Toolkit — enterprise-grade compliance components for the Nigeria Data Protection Act (NDPA) 2023",
6
6
  "pnpm": {
@@ -303,7 +303,7 @@
303
303
  "class-variance-authority": "^0.7.1",
304
304
  "clsx": "^2.1.1",
305
305
  "docx": ">=8.0.0",
306
- "jspdf": "^3.0.3",
306
+ "jspdf": "^3.0.3 || ^4.2.1",
307
307
  "react": "^18.0.0 || ^19.0.0",
308
308
  "react-dom": "^18.0.0 || ^19.0.0",
309
309
  "tailwind-merge": "^2.6.0"