@tantainnovative/ndpr-toolkit 3.10.6 → 3.12.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 +111 -0
- package/README.md +38 -24
- package/dist/adapters.d.mts +90 -4
- package/dist/adapters.d.ts +90 -4
- package/dist/breach.d.mts +13 -1
- package/dist/breach.d.ts +13 -1
- package/dist/breach.js +1 -1
- package/dist/breach.mjs +1 -1
- package/dist/{chunk-EZCGTHQV.js → chunk-4GIMXUMI.js} +3 -3
- package/dist/{chunk-HBLGN4SD.js → chunk-5AECGMEB.js} +1 -1
- package/dist/chunk-67KA345Q.mjs +1 -0
- package/dist/chunk-6OWCUDTN.mjs +1 -0
- package/dist/{chunk-4G3SRVRI.mjs → chunk-B6BRD5SL.mjs} +1 -1
- package/dist/chunk-CAFCRCTZ.mjs +1 -0
- package/dist/{chunk-VJTQXVAF.js → chunk-EHQVTFYO.js} +1 -1
- package/dist/{chunk-CNM6G5IA.js → chunk-FC3PTJFL.js} +1 -1
- package/dist/{chunk-H3IULCE3.js → chunk-HOAC5VUF.js} +1 -1
- package/dist/{chunk-H3XJV2IR.mjs → chunk-I3V3ITN7.mjs} +1 -1
- package/dist/{chunk-MPBPAEZC.mjs → chunk-IB3KSUPZ.mjs} +1 -1
- package/dist/{chunk-TAHSSITO.mjs → chunk-IHNAFXDM.mjs} +1 -1
- package/dist/chunk-IQO3SIAG.mjs +1 -0
- package/dist/{chunk-UTFBKL73.js → chunk-IRRUYR6M.js} +1 -1
- package/dist/{chunk-C7IDR2IV.js → chunk-JLQT3W3E.js} +1 -1
- package/dist/chunk-JYZOKO2W.mjs +103 -0
- package/dist/chunk-NX5MOBRI.js +1 -0
- package/dist/chunk-O2WEABB3.js +1 -0
- package/dist/chunk-OZHUINWS.js +1 -0
- package/dist/{chunk-66NQ5CVY.mjs → chunk-Q4CSVWSS.mjs} +1 -1
- package/dist/{chunk-CR2QZTGW.js → chunk-QMAVEHOR.js} +1 -1
- package/dist/{chunk-3HOXQNCH.mjs → chunk-RFXGD5NE.mjs} +1 -1
- package/dist/chunk-ROC64RLP.js +1 -0
- package/dist/{chunk-O45PKBZA.mjs → chunk-RR3KXNET.mjs} +3 -3
- package/dist/{chunk-KY6WYHWB.mjs → chunk-TN4TH3CT.mjs} +1 -1
- package/dist/chunk-VPNK7OID.mjs +1 -0
- package/dist/{chunk-O2RDZGM2.js → chunk-VUFTRKKC.js} +1 -1
- package/dist/chunk-WKUC65HL.mjs +1 -0
- package/dist/chunk-WXUXCRAJ.js +1 -0
- package/dist/chunk-YK22SYCT.js +103 -0
- package/dist/chunk-YSD2DFBR.js +6 -0
- package/dist/chunk-ZHX62QAL.mjs +6 -0
- package/dist/consent.d.mts +23 -1
- package/dist/consent.d.ts +23 -1
- package/dist/consent.js +1 -1
- package/dist/consent.mjs +1 -1
- package/dist/core.js +1 -1
- package/dist/core.mjs +1 -1
- package/dist/cross-border.d.mts +12 -1
- package/dist/cross-border.d.ts +12 -1
- package/dist/cross-border.js +1 -1
- package/dist/cross-border.mjs +1 -1
- package/dist/dpia.d.mts +16 -1
- package/dist/dpia.d.ts +16 -1
- package/dist/dpia.js +1 -1
- package/dist/dpia.mjs +1 -1
- package/dist/dsr.d.mts +21 -1
- package/dist/dsr.d.ts +21 -1
- package/dist/dsr.js +1 -1
- package/dist/dsr.mjs +1 -1
- package/dist/headless.d.mts +217 -24
- package/dist/headless.d.ts +217 -24
- package/dist/headless.js +1 -1
- package/dist/headless.mjs +1 -1
- package/dist/hooks.d.mts +217 -24
- package/dist/hooks.d.ts +217 -24
- package/dist/hooks.js +1 -1
- package/dist/hooks.mjs +1 -1
- package/dist/index.d.mts +419 -29
- package/dist/index.d.ts +419 -29
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/lawful-basis.d.mts +10 -0
- package/dist/lawful-basis.d.ts +10 -0
- package/dist/lawful-basis.js +1 -1
- package/dist/lawful-basis.mjs +1 -1
- package/dist/policy.d.mts +39 -1
- package/dist/policy.d.ts +39 -1
- package/dist/presets.js +1 -1
- package/dist/presets.mjs +1 -1
- package/dist/ropa.d.mts +39 -3
- package/dist/ropa.d.ts +39 -3
- package/dist/ropa.js +1 -1
- package/dist/ropa.mjs +1 -1
- package/dist/server.d.mts +86 -0
- package/dist/server.d.ts +86 -0
- package/dist/server.js +1 -1
- package/dist/server.mjs +1 -1
- package/dist/styles.css +2 -0
- package/package.json +1 -1
- package/dist/chunk-3JPDTXGC.js +0 -1
- package/dist/chunk-43OQNS2J.mjs +0 -6
- package/dist/chunk-5GVMKUMP.js +0 -1
- package/dist/chunk-COD3RMTL.mjs +0 -1
- package/dist/chunk-EXEXUAF6.mjs +0 -1
- package/dist/chunk-L2BRFMVS.js +0 -1
- package/dist/chunk-MOHBL6LX.mjs +0 -1
- package/dist/chunk-PGI2LM6P.js +0 -103
- package/dist/chunk-PZRQWPWD.js +0 -1
- package/dist/chunk-RPXRPGHL.mjs +0 -1
- package/dist/chunk-RZ6GC6WN.mjs +0 -1
- package/dist/chunk-SSH4U4TJ.js +0 -6
- package/dist/chunk-WDDCKYWA.js +0 -1
- package/dist/chunk-X3GCGC3H.mjs +0 -103
- package/dist/chunk-ZQZJNKVB.mjs +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,117 @@
|
|
|
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
|
+
## [3.12.0](https://github.com/mr-tanta/ndpr-toolkit/compare/v3.11.0...v3.12.0) (2026-05-27)
|
|
6
|
+
|
|
7
|
+
Release 4 of 6 on the post-audit roadmap. Accessibility + performance + test coverage. No public API changes — everything is additive or behaviour-preserving internal work. Existing consumers see no breakage; users of assistive tech and consumers of large managers see real improvements.
|
|
8
|
+
|
|
9
|
+
### Accessibility — 6 WCAG 2.2 fixes
|
|
10
|
+
|
|
11
|
+
- **`BreachNotificationManager`** (`components/breach/BreachNotificationManager.tsx`) — the breach list row was a clickable `<div>` without `role`/`tabIndex`/keyboard handler. Now `role="button"`, `tabIndex={0}`, `aria-selected`, `aria-label`, and Enter/Space activation (matching the existing DSRDashboard pattern). Keyboard users can finally drill into a breach row.
|
|
12
|
+
- **`dpia/StepIndicator`** — the step wedge had `onClick` without button semantics. Now conditionally adds `role="button"` / `tabIndex` / keydown when interactive (`clickable && onStepClick`); when display-only, those attributes are `undefined` so it stays a non-interactive progress marker.
|
|
13
|
+
- **`CrossBorderTransferManager`** — 8 form fields had `<label>` without `htmlFor` and the matching `<input>`/`<select>` had no `id`. Screen readers announced "edit text, blank" for all 8. Added stable `cb-transfer-<field>` id pairs: `riskLevel`, `estimatedDataSubjects`, `recipientContactPhone`, `recipientContactAddress`, `frequency`, `status`, `ndpcApprovalReference`, `tiaReference`.
|
|
14
|
+
- **`BreachReportForm` file upload** — `<label>` had no `htmlFor`, `<input type="file">` had no `id`. Added `htmlFor="breach-attachments"` + matching id. Decorative paperclip SVG got `aria-hidden="true" focusable="false"`.
|
|
15
|
+
- **Touch targets** — `.ndpr-consent-banner__button` and `.ndpr-button` were ~33px tall (`padding: 0.5rem 1rem`). Added `min-height: 44px` to both — matches iOS HIG and WCAG 2.2 enhanced target. Existing padding is unchanged so visual layout doesn't shift.
|
|
16
|
+
- **`DPIAQuestionnaire`** — section title heading now has `aria-live="polite"` so screen readers announce the new section title when the user clicks Next.
|
|
17
|
+
|
|
18
|
+
### Performance — 3 hot-path improvements
|
|
19
|
+
|
|
20
|
+
- **`useROPA`** (`hooks/useROPA.ts`) — derivers `getSummary` / `exportCSV` / `getComplianceGaps` previously recomputed on every call. Hook now also returns `summary` / `csv` / `complianceGaps` as `useMemo`-cached values keyed on `ropa`. The existing callable functions still work (marked `@deprecated` in JSDoc, points at the cached fields). Pure additive — no break.
|
|
21
|
+
- **`CrossBorderTransferManager`** — `summaryData` collapsed from 4× `transfers.filter(...)` calls (O(4n)) to a single `for` loop (O(n)) that accumulates `totalActiveTransfers`, `pendingApproval`, `highRiskTransfers`, `missingTIA` in one pass. Same output shape; meaningfully faster with many transfers.
|
|
22
|
+
- **Hoisted lookup tables** — `STATUS_BADGE_CLASSES` / `STATUS_BADGE_LABELS` / `BASIS_BADGE_CLASSES` / `BASIS_BADGE_LABELS` (LawfulBasisTracker), `RISK_BADGE_CLASSES` / `CB_STATUS_BADGE_*` (CrossBorderTransferManager), `ROPA_STATUS_BADGE_*` / `ROPA_BASIS_BADGE_LABELS` (ROPAManager) moved from inside `useCallback` bodies to module scope. Eliminates per-row object allocation on every render.
|
|
23
|
+
|
|
24
|
+
Two perf items from the audit were **inspected and intentionally skipped** with documented reasons:
|
|
25
|
+
|
|
26
|
+
- `useDefaultPrivacyPolicy` was already cached via a `useRef`-gated init (not a typical `useMemo` shape, but functionally equivalent — the comment at line 167 calls out the intentional semantics).
|
|
27
|
+
- `ROPAManager` inline onChange closures were already paired with `useCallback`-stable `updateEditingField` / `updateControllerField` refs, so the existing setup doesn't pay the per-keystroke closure-allocation cost we'd hoped to remove. Extracting a `<FormField>` component would touch >400 lines and risk subtle behavioural change for marginal gain.
|
|
28
|
+
|
|
29
|
+
### Test coverage — +25 cases
|
|
30
|
+
|
|
31
|
+
Suite jumped from 1212 to **1237 / 1237 passing**. New cases target gaps the audit's B4 report flagged as critical:
|
|
32
|
+
|
|
33
|
+
- **`useFocusTrap`** (7 cases, new file) — restore-focus-on-deactivation, Tab cycling forward, Shift+Tab cycling backward, onEscape, listener cleanup, `autoFocus: false`. Previously zero dedicated tests for 128 LOC of WCAG-critical focus-trap logic.
|
|
34
|
+
- **`useComplianceScore`** (2 cases, new file) — memoisation by deep equality, recompute on inner-field change.
|
|
35
|
+
- **`NDPRDashboard` preset** (2 cases, new file) — `ComplianceInput` → score ring; degraded input lowers score.
|
|
36
|
+
- **`NDPRThemeProvider`** (2 added cases) — `mode: 'light'` sets `data-theme="light"`; empty `theme={{}}` produces no style attribute.
|
|
37
|
+
- **`assessDPIARisk`** (2 added cases) — empty-risks array → low-level; all-mitigated high-risk → `canProceed: true`.
|
|
38
|
+
- **`NDPRProvider`** (3 cases, new file) — `useNDPRConfig` returns provided config; `useNDPRLocale` merges partial overrides with English defaults; nested-provider innermost-wins.
|
|
39
|
+
- **`preset-callbacks`** (7 cases, new file) — submit / save / complete callbacks across `NDPRConsent`, `NDPRBreachReport` (with adapter), `NDPRDPIA`, `NDPRLawfulBasis`, `NDPRCrossBorder`, `NDPRROPA`. (One preset deferred: `NDPRPrivacyPolicy.onComplete` only fires after a multi-step wizard flow with valid data — would duplicate `useAdaptivePolicyWizard`'s own tests.)
|
|
40
|
+
|
|
41
|
+
### Deferred from the original 3.12.0 plan
|
|
42
|
+
|
|
43
|
+
- **`/server` split into `/server/utils`, `/server/policy`, `/server/locales`.** Inspected: the 261-line `/server` re-exports translate to ~40 chunks pulled by tsup, but consumers already have narrower subpaths (`/dsr`, `/policy`, etc.) for the same use cases. The split adds 3 entry points + 3 PROBES + 3 docs entries for marginal benefit. Slated for re-evaluation in the 4.x roadmap discussion alongside the B20 strategic items.
|
|
44
|
+
|
|
45
|
+
### Verification
|
|
46
|
+
|
|
47
|
+
- Jest: **1237 / 1237 passing** (was 1212; +25 new tests)
|
|
48
|
+
- `tsc --noEmit -p tsconfig.json` clean
|
|
49
|
+
- `pnpm verify:tarball --skip-ts` clean across all 22 subpaths
|
|
50
|
+
|
|
51
|
+
## [3.11.0](https://github.com/mr-tanta/ndpr-toolkit/compare/v3.10.6...v3.11.0) (2026-05-27)
|
|
52
|
+
|
|
53
|
+
Release 3 of 6 on the post-audit roadmap. Strictly additive — every change here adds to the public surface or fixes a docs lie. Existing consumers keep working without changes.
|
|
54
|
+
|
|
55
|
+
### Type-export baseline — `*Props` interfaces, adapter ecosystem types, hook return types now reachable
|
|
56
|
+
|
|
57
|
+
Every component's `Props` interface is now re-exported from `src/index.ts` (the default entry):
|
|
58
|
+
|
|
59
|
+
`ConsentBannerProps`, `ConsentManagerProps`, `ConsentStorageProps`, `DSRRequestFormProps`, `DSRDashboardProps`, `DSRTrackerProps`, `DPIAQuestionnaireProps`, `DPIAReportProps`, `StepIndicatorProps`, `BreachReportFormProps`, `BreachRiskAssessmentProps`, `BreachNotificationManagerProps`, `RegulatoryReportGeneratorProps`, `PolicyGeneratorProps`, `PolicyPreviewProps`, `PolicyExporterProps`, `LawfulBasisTrackerProps`, `CrossBorderTransferManagerProps`, `ROPAManagerProps`.
|
|
60
|
+
|
|
61
|
+
Consumers can now type-safely wrap the toolkit's components — e.g.
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import type { ConsentBannerProps, NDPRThemeProvider } from '@tantainnovative/ndpr-toolkit';
|
|
65
|
+
|
|
66
|
+
function MyConsentBanner(props: ConsentBannerProps & { brand?: string }) { … }
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Adapter ecosystem types reachable too:
|
|
70
|
+
- `ApiAdapterErrorContext<T>`, `ApiAdapterSuccessContext<T>`, `ApiAdapterRetryConfig`, `ApiAdapterMethod` from `/adapters` and root
|
|
71
|
+
- `CookieAdapterOptions`, `StorageAdapter<T>` from `/adapters` and root
|
|
72
|
+
|
|
73
|
+
DSR validator types reachable:
|
|
74
|
+
- `DsrSubmissionPayload`, `DsrSubmissionValidationResult`, `ValidateDsrSubmissionOptions` from `/server` (canonical) and root
|
|
75
|
+
|
|
76
|
+
Hook option/return interfaces promoted to `export interface` and re-exported through `hooks-entry.ts` (auto-flows to `/headless`):
|
|
77
|
+
- `UseConsentOptions`/`Return`, `UseDSROptions`, `UseBreachOptions`, `UseDPIAOptions`, `UseLawfulBasisOptions`, `UseCrossBorderTransferOptions`, `UseComplianceScoreOptions`, `UsePrivacyPolicyOptions`.
|
|
78
|
+
|
|
79
|
+
### JSDoc `@example` blocks on every public hook + adapter
|
|
80
|
+
|
|
81
|
+
Added `@example` blocks to all 10 public hooks (`useConsent`, `useDSR`, `useBreach`, `useDPIA`, `useLawfulBasis`, `useCrossBorderTransfer`, `usePrivacyPolicy`, `useROPA`, `useAdaptivePolicyWizard`, `useComplianceScore`) and 5 adapters (`cookieAdapter`, `localStorageAdapter`, `sessionStorageAdapter`, `memoryAdapter`, `composeAdapters`). `useComplianceScore` previously had zero JSDoc; full block added (description + `@param` + `@returns` + `@example`).
|
|
82
|
+
|
|
83
|
+
### Internal: `validateDsrSubmission` type-guard refactor
|
|
84
|
+
|
|
85
|
+
Replaced the `as string` cast chain in `utils/dsr.ts` with a `isDsrPayloadRaw(payload): payload is DsrPayloadRaw` type guard. External signature unchanged. Safer narrowing; no consumer-visible difference.
|
|
86
|
+
|
|
87
|
+
### Docs
|
|
88
|
+
|
|
89
|
+
**9 new component pages** under `src/app/docs/components/`, all wired into the sidebar nav:
|
|
90
|
+
|
|
91
|
+
- `ndpr-theme-provider`, `ndpr-provider`, `ndpr-dashboard`, `adaptive-policy-wizard`, `policy-page`, `legal-notice` (previously had no dedicated pages)
|
|
92
|
+
- `lawful-basis-tracker-lite`, `cross-border-transfer-manager-lite`, `ropa-manager-lite` (Lite variants previously only mentioned inline)
|
|
93
|
+
|
|
94
|
+
**Fixed broken docs** that taught fictitious symbol names:
|
|
95
|
+
- 5 `useDSR()` calls without the required `requestTypes` arg, in `components/data-subject-rights/page.tsx`, `components/hooks/page.tsx`, and `guides/data-subject-requests/page.tsx`. All now show `useDSR({ requestTypes })` with the correct API.
|
|
96
|
+
- `getRequestById` → `getRequest`, `filterRequestsByStatus` → `getRequestsByStatus`, `filterRequestsByType` → `getRequestsByType` (the docs were inventing names that don't exist). `deleteRequest` removed — no such function ships.
|
|
97
|
+
- `onSubmit` prop on the DSR component page now typed `DSRFormSubmission`, not the fictitious `DSRFormData`.
|
|
98
|
+
|
|
99
|
+
### README compact pass
|
|
100
|
+
|
|
101
|
+
- Bumped version refs `v3.10.3` → `v3.11.0` (6 occurrences: header release link + 5 screenshot URL tags).
|
|
102
|
+
- Replaced the 3-File Quickstart's throwaway `let store: unknown = null` API route with a clean 2-file quickstart that uses `localStorageAdapter` by default and shows `cookieAdapter` / `apiAdapter` / `composeAdapters` as opt-ins. The throwaway demo always looked unprofessional next to claims of production-readiness.
|
|
103
|
+
- New **"When NOT to use this toolkit"** section between Adapters and Pluggable Storage. Honest framing: non-React stacks, banner-only use cases, GDPR-primary regimes, enterprise CMP shoppers should pick something else. Builds trust with the people who are the right fit.
|
|
104
|
+
- "What's new" notice rewritten for 3.11.0 (less narrative, more skimmable).
|
|
105
|
+
|
|
106
|
+
### CONTRIBUTING.md rewritten
|
|
107
|
+
|
|
108
|
+
The previous file was generic boilerplate. The new one covers the practical things contributors actually need: pnpm 10 / Node ≥20 setup, repo layout (with a callout that the root `package.json` is the publish surface, not the inner one), how to run a single test, the `verify:tarball` gate, the release flow, branch conventions, patch/minor/major decision table, i18n contribution guide.
|
|
109
|
+
|
|
110
|
+
### Verification
|
|
111
|
+
|
|
112
|
+
- Jest: **1212 / 1212 passing** (no behaviour changes)
|
|
113
|
+
- `tsc --noEmit -p tsconfig.json` — clean
|
|
114
|
+
- `pnpm verify:tarball --skip-ts` — clean across all 22 subpaths
|
|
115
|
+
|
|
5
116
|
## [3.10.6](https://github.com/mr-tanta/ndpr-toolkit/compare/v3.10.5...v3.10.6) (2026-05-27)
|
|
6
117
|
|
|
7
118
|
Release 2 of 6 on the post-audit roadmap. CI / repo plumbing only — zero `dist/` changes, zero behaviour changes for consumers.
|
package/README.md
CHANGED
|
@@ -11,28 +11,29 @@
|
|
|
11
11
|
|
|
12
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.
|
|
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.
|
|
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)**
|
|
15
15
|
|
|
16
16
|
[](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/nextjs-app)
|
|
17
17
|
[](https://codesandbox.io/p/github/mr-tanta/ndpr-toolkit/main/examples/nextjs-app)
|
|
18
18
|
|
|
19
|
-
> **What's new in 3.
|
|
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`.
|
|
20
20
|
>
|
|
21
|
-
> **Upgrading from 3.7.x
|
|
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-prod/`, 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).
|
|
22
22
|
|
|
23
23
|
<p align="center">
|
|
24
|
-
<img src="https://raw.githubusercontent.com/mr-tanta/ndpr-toolkit/v3.
|
|
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" />
|
|
25
25
|
</p>
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
29
|
-
##
|
|
29
|
+
## Quickstart
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
Two files. Full NDPA-compliant consent with no backend.
|
|
32
32
|
|
|
33
33
|
**`app/layout.tsx`**
|
|
34
34
|
```tsx
|
|
35
35
|
import { NDPRConsent } from '@tantainnovative/ndpr-toolkit/presets';
|
|
36
|
+
import '@tantainnovative/ndpr-toolkit/styles';
|
|
36
37
|
|
|
37
38
|
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
38
39
|
return (
|
|
@@ -46,31 +47,31 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|
|
46
47
|
}
|
|
47
48
|
```
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
```ts
|
|
51
|
-
import { NextRequest, NextResponse } from 'next/server';
|
|
52
|
-
|
|
53
|
-
let store: unknown = null;
|
|
50
|
+
That's it — `NDPRConsent` defaults to `localStorageAdapter`, so consent persists across page loads with zero backend code.
|
|
54
51
|
|
|
55
|
-
|
|
56
|
-
export async function POST(req: NextRequest) {
|
|
57
|
-
store = await req.json();
|
|
58
|
-
return NextResponse.json({ ok: true });
|
|
59
|
-
}
|
|
60
|
-
```
|
|
52
|
+
**Want server-side persistence?** Pass any `StorageAdapter`:
|
|
61
53
|
|
|
62
|
-
**Persist to your API instead of localStorage:**
|
|
63
54
|
```tsx
|
|
64
55
|
import { NDPRConsent } from '@tantainnovative/ndpr-toolkit/presets';
|
|
65
|
-
import { apiAdapter } from '@tantainnovative/ndpr-toolkit/adapters';
|
|
56
|
+
import { cookieAdapter, apiAdapter, composeAdapters, localStorageAdapter } from '@tantainnovative/ndpr-toolkit/adapters';
|
|
66
57
|
|
|
58
|
+
// Server-readable cookie (best for SSR consent gating)
|
|
59
|
+
<NDPRConsent adapter={cookieAdapter('ndpr_consent', { expires: 180 })} />
|
|
60
|
+
|
|
61
|
+
// Or POST to your own backend
|
|
67
62
|
<NDPRConsent adapter={apiAdapter('/api/consent')} />
|
|
63
|
+
|
|
64
|
+
// Or both — fan-out writes
|
|
65
|
+
<NDPRConsent adapter={composeAdapters(
|
|
66
|
+
apiAdapter('/api/consent'),
|
|
67
|
+
localStorageAdapter('ndpr_consent'),
|
|
68
|
+
)} />
|
|
68
69
|
```
|
|
69
70
|
|
|
70
|
-
|
|
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).
|
|
71
72
|
|
|
72
73
|
<p align="center">
|
|
73
|
-
<img src="https://raw.githubusercontent.com/mr-tanta/ndpr-toolkit/v3.
|
|
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
75
|
<br />
|
|
75
76
|
<em>Interactive consent demo with configurable position, theme, storage, and real-time state inspector</em>
|
|
76
77
|
</p>
|
|
@@ -304,6 +305,19 @@ import { apiAdapter, localStorageAdapter, cookieAdapter } from '@tantainnovative
|
|
|
304
305
|
|
|
305
306
|
---
|
|
306
307
|
|
|
308
|
+
## When NOT to use this toolkit
|
|
309
|
+
|
|
310
|
+
The toolkit is React-first, NDPA-specific, and built for product engineers shipping a compliant app — not a generic cookie-banner library. Pick something else if:
|
|
311
|
+
|
|
312
|
+
- **You're not on React.** No Vue / Svelte / Angular bindings exist. The `/server` entry exposes framework-agnostic validators and the compliance-score engine — usable from any Node runtime — but the UI components are React-only.
|
|
313
|
+
- **You only need a cookie banner**, with no DSR portal, breach reporting, DPIA, ROPA, or compliance scoring. A purpose-built consent library (Iubenda, OneTrust, Cookiebot, Osano) is a better fit and will integrate with your CMP / TCF setup. The toolkit can do the banner alone, but you'd be paying for surface you don't use.
|
|
314
|
+
- **Your compliance regime is GDPR / CCPA-primary** and you don't operate under the Nigeria Data Protection Act 2023. The validators, statutory deadlines, and section citations are NDPA-specific. (NDPA + GDPR overlap a lot in practice; the toolkit doesn't pretend to be a GDPR product.)
|
|
315
|
+
- **You need an enterprise consent-management platform** with audit trails, marketing-team UIs, regional CMP exports, and a vendor SLA. That's a different product category.
|
|
316
|
+
|
|
317
|
+
The toolkit is what we wished existed when building Nigerian SaaS apps in 2025 and need NDPA components that don't fight the rest of the stack. If that's your shape, read on.
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
307
321
|
## Pluggable Storage
|
|
308
322
|
|
|
309
323
|
Every stateful component accepts an `adapter` prop. Built-in adapters ship out of the box.
|
|
@@ -434,13 +448,13 @@ Every module has an interactive demo. No signup, no setup — try them instantly
|
|
|
434
448
|
|
|
435
449
|
<p align="center">
|
|
436
450
|
<a href="https://ndprtoolkit.com.ng/ndpr-demos">
|
|
437
|
-
<img src="https://raw.githubusercontent.com/mr-tanta/ndpr-toolkit/v3.
|
|
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" />
|
|
438
452
|
</a>
|
|
439
453
|
</p>
|
|
440
454
|
|
|
441
455
|
<p align="center">
|
|
442
|
-
<img src="https://raw.githubusercontent.com/mr-tanta/ndpr-toolkit/v3.
|
|
443
|
-
<img src="https://raw.githubusercontent.com/mr-tanta/ndpr-toolkit/v3.
|
|
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" />
|
|
444
458
|
</p>
|
|
445
459
|
|
|
446
460
|
<p align="center">
|
package/dist/adapters.d.mts
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
*/
|
|
33
33
|
export declare function apiAdapter<T = unknown>(endpoint: string, options?: ApiAdapterOptions<T>): StorageAdapter<T>;
|
|
34
34
|
|
|
35
|
-
declare interface ApiAdapterErrorContext<T = unknown> {
|
|
35
|
+
export declare interface ApiAdapterErrorContext<T = unknown> {
|
|
36
36
|
/** Which adapter operation triggered this — `load`, `save`, or `remove`. */
|
|
37
37
|
method: ApiAdapterMethod;
|
|
38
38
|
/** The endpoint URL that failed. */
|
|
@@ -49,7 +49,7 @@ declare interface ApiAdapterErrorContext<T = unknown> {
|
|
|
49
49
|
attempt: number;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
declare type ApiAdapterMethod = 'load' | 'save' | 'remove';
|
|
52
|
+
export declare type ApiAdapterMethod = 'load' | 'save' | 'remove';
|
|
53
53
|
|
|
54
54
|
export declare interface ApiAdapterOptions<T = unknown> {
|
|
55
55
|
/**
|
|
@@ -106,7 +106,7 @@ export declare interface ApiAdapterOptions<T = unknown> {
|
|
|
106
106
|
fetchInit?: Omit<RequestInit, 'method' | 'headers' | 'body' | 'credentials'>;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
declare interface ApiAdapterRetryConfig {
|
|
109
|
+
export declare interface ApiAdapterRetryConfig {
|
|
110
110
|
/**
|
|
111
111
|
* Number of additional attempts after the initial request. Defaults to 0
|
|
112
112
|
* (no retries). e.g. `attempts: 2` means up to 3 total requests.
|
|
@@ -125,7 +125,7 @@ declare interface ApiAdapterRetryConfig {
|
|
|
125
125
|
shouldRetry?: (ctx: ApiAdapterErrorContext<unknown>) => boolean;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
declare interface ApiAdapterSuccessContext<T = unknown> {
|
|
128
|
+
export declare interface ApiAdapterSuccessContext<T = unknown> {
|
|
129
129
|
/** Which adapter operation succeeded — `load`, `save`, or `remove`. */
|
|
130
130
|
method: ApiAdapterMethod;
|
|
131
131
|
/** The endpoint URL. */
|
|
@@ -138,8 +138,51 @@ declare interface ApiAdapterSuccessContext<T = unknown> {
|
|
|
138
138
|
payload?: T;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
/**
|
|
142
|
+
* Compose a primary adapter with one or more secondary adapters. Reads
|
|
143
|
+
* always go to the primary; writes (`save` / `remove`) fan out to the
|
|
144
|
+
* primary first, then each secondary. Secondary failures are logged but
|
|
145
|
+
* never propagated.
|
|
146
|
+
*
|
|
147
|
+
* Useful for shadowing localStorage to an API endpoint, mirroring consent
|
|
148
|
+
* to a cookie for SSR, or building offline-first sync.
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```ts
|
|
152
|
+
* import {
|
|
153
|
+
* composeAdapters,
|
|
154
|
+
* localStorageAdapter,
|
|
155
|
+
* apiAdapter,
|
|
156
|
+
* } from '@tantainnovative/ndpr-toolkit/adapters';
|
|
157
|
+
* import { useConsent } from '@tantainnovative/ndpr-toolkit/hooks';
|
|
158
|
+
*
|
|
159
|
+
* const adapter = composeAdapters(
|
|
160
|
+
* localStorageAdapter('ndpr_consent'),
|
|
161
|
+
* apiAdapter('/api/consent'),
|
|
162
|
+
* );
|
|
163
|
+
* useConsent({ options, adapter });
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
141
166
|
export declare function composeAdapters<T = unknown>(primary: StorageAdapter<T>, ...secondaries: StorageAdapter<T>[]): StorageAdapter<T>;
|
|
142
167
|
|
|
168
|
+
/**
|
|
169
|
+
* Storage adapter backed by a browser cookie. Useful for consent state that
|
|
170
|
+
* needs to be shared with server-side rendering, or for cross-subdomain
|
|
171
|
+
* persistence via the `domain` option.
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```ts
|
|
175
|
+
* import { cookieAdapter } from '@tantainnovative/ndpr-toolkit/adapters';
|
|
176
|
+
* import { useConsent } from '@tantainnovative/ndpr-toolkit/hooks';
|
|
177
|
+
*
|
|
178
|
+
* const adapter = cookieAdapter('ndpr_consent', {
|
|
179
|
+
* domain: '.example.com',
|
|
180
|
+
* sameSite: 'Lax',
|
|
181
|
+
* expires: 180,
|
|
182
|
+
* });
|
|
183
|
+
* useConsent({ options, adapter });
|
|
184
|
+
* ```
|
|
185
|
+
*/
|
|
143
186
|
export declare function cookieAdapter<T = unknown>(key: string, options?: CookieAdapterOptions): StorageAdapter<T>;
|
|
144
187
|
|
|
145
188
|
export declare interface CookieAdapterOptions {
|
|
@@ -150,10 +193,53 @@ export declare interface CookieAdapterOptions {
|
|
|
150
193
|
sameSite?: 'Strict' | 'Lax' | 'None';
|
|
151
194
|
}
|
|
152
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Storage adapter backed by `window.localStorage`. The default adapter used
|
|
198
|
+
* by every hook in the toolkit when no `adapter` prop is supplied.
|
|
199
|
+
*
|
|
200
|
+
* Safe to import server-side — every method short-circuits when
|
|
201
|
+
* `window` is undefined, so calling `load()` on the server returns `null`.
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* ```ts
|
|
205
|
+
* import { localStorageAdapter } from '@tantainnovative/ndpr-toolkit/adapters';
|
|
206
|
+
* import { useConsent } from '@tantainnovative/ndpr-toolkit/hooks';
|
|
207
|
+
*
|
|
208
|
+
* const adapter = localStorageAdapter('ndpr_consent');
|
|
209
|
+
* useConsent({ options, adapter });
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
153
212
|
export declare function localStorageAdapter<T = unknown>(key: string): StorageAdapter<T>;
|
|
154
213
|
|
|
214
|
+
/**
|
|
215
|
+
* Storage adapter backed by an in-memory value. Useful in tests, Storybook,
|
|
216
|
+
* SSR previews, or anywhere persistence across reloads is undesirable.
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* ```ts
|
|
220
|
+
* import { memoryAdapter } from '@tantainnovative/ndpr-toolkit/adapters';
|
|
221
|
+
* import { useConsent } from '@tantainnovative/ndpr-toolkit/hooks';
|
|
222
|
+
*
|
|
223
|
+
* const adapter = memoryAdapter({ consents: {}, version: '1.0' });
|
|
224
|
+
* useConsent({ options, adapter });
|
|
225
|
+
* ```
|
|
226
|
+
*/
|
|
155
227
|
export declare function memoryAdapter<T = unknown>(initialData?: T): StorageAdapter<T>;
|
|
156
228
|
|
|
229
|
+
/**
|
|
230
|
+
* Storage adapter backed by `window.sessionStorage`. Data is scoped to the
|
|
231
|
+
* current tab and discarded when the tab closes — useful for consent
|
|
232
|
+
* choices that should not survive a fresh session.
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```ts
|
|
236
|
+
* import { sessionStorageAdapter } from '@tantainnovative/ndpr-toolkit/adapters';
|
|
237
|
+
* import { useConsent } from '@tantainnovative/ndpr-toolkit/hooks';
|
|
238
|
+
*
|
|
239
|
+
* const adapter = sessionStorageAdapter('ndpr_consent');
|
|
240
|
+
* useConsent({ options, adapter });
|
|
241
|
+
* ```
|
|
242
|
+
*/
|
|
157
243
|
export declare function sessionStorageAdapter<T = unknown>(key: string): StorageAdapter<T>;
|
|
158
244
|
|
|
159
245
|
export declare interface StorageAdapter<T = unknown> {
|
package/dist/adapters.d.ts
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
*/
|
|
33
33
|
export declare function apiAdapter<T = unknown>(endpoint: string, options?: ApiAdapterOptions<T>): StorageAdapter<T>;
|
|
34
34
|
|
|
35
|
-
declare interface ApiAdapterErrorContext<T = unknown> {
|
|
35
|
+
export declare interface ApiAdapterErrorContext<T = unknown> {
|
|
36
36
|
/** Which adapter operation triggered this — `load`, `save`, or `remove`. */
|
|
37
37
|
method: ApiAdapterMethod;
|
|
38
38
|
/** The endpoint URL that failed. */
|
|
@@ -49,7 +49,7 @@ declare interface ApiAdapterErrorContext<T = unknown> {
|
|
|
49
49
|
attempt: number;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
declare type ApiAdapterMethod = 'load' | 'save' | 'remove';
|
|
52
|
+
export declare type ApiAdapterMethod = 'load' | 'save' | 'remove';
|
|
53
53
|
|
|
54
54
|
export declare interface ApiAdapterOptions<T = unknown> {
|
|
55
55
|
/**
|
|
@@ -106,7 +106,7 @@ export declare interface ApiAdapterOptions<T = unknown> {
|
|
|
106
106
|
fetchInit?: Omit<RequestInit, 'method' | 'headers' | 'body' | 'credentials'>;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
declare interface ApiAdapterRetryConfig {
|
|
109
|
+
export declare interface ApiAdapterRetryConfig {
|
|
110
110
|
/**
|
|
111
111
|
* Number of additional attempts after the initial request. Defaults to 0
|
|
112
112
|
* (no retries). e.g. `attempts: 2` means up to 3 total requests.
|
|
@@ -125,7 +125,7 @@ declare interface ApiAdapterRetryConfig {
|
|
|
125
125
|
shouldRetry?: (ctx: ApiAdapterErrorContext<unknown>) => boolean;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
declare interface ApiAdapterSuccessContext<T = unknown> {
|
|
128
|
+
export declare interface ApiAdapterSuccessContext<T = unknown> {
|
|
129
129
|
/** Which adapter operation succeeded — `load`, `save`, or `remove`. */
|
|
130
130
|
method: ApiAdapterMethod;
|
|
131
131
|
/** The endpoint URL. */
|
|
@@ -138,8 +138,51 @@ declare interface ApiAdapterSuccessContext<T = unknown> {
|
|
|
138
138
|
payload?: T;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
/**
|
|
142
|
+
* Compose a primary adapter with one or more secondary adapters. Reads
|
|
143
|
+
* always go to the primary; writes (`save` / `remove`) fan out to the
|
|
144
|
+
* primary first, then each secondary. Secondary failures are logged but
|
|
145
|
+
* never propagated.
|
|
146
|
+
*
|
|
147
|
+
* Useful for shadowing localStorage to an API endpoint, mirroring consent
|
|
148
|
+
* to a cookie for SSR, or building offline-first sync.
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```ts
|
|
152
|
+
* import {
|
|
153
|
+
* composeAdapters,
|
|
154
|
+
* localStorageAdapter,
|
|
155
|
+
* apiAdapter,
|
|
156
|
+
* } from '@tantainnovative/ndpr-toolkit/adapters';
|
|
157
|
+
* import { useConsent } from '@tantainnovative/ndpr-toolkit/hooks';
|
|
158
|
+
*
|
|
159
|
+
* const adapter = composeAdapters(
|
|
160
|
+
* localStorageAdapter('ndpr_consent'),
|
|
161
|
+
* apiAdapter('/api/consent'),
|
|
162
|
+
* );
|
|
163
|
+
* useConsent({ options, adapter });
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
141
166
|
export declare function composeAdapters<T = unknown>(primary: StorageAdapter<T>, ...secondaries: StorageAdapter<T>[]): StorageAdapter<T>;
|
|
142
167
|
|
|
168
|
+
/**
|
|
169
|
+
* Storage adapter backed by a browser cookie. Useful for consent state that
|
|
170
|
+
* needs to be shared with server-side rendering, or for cross-subdomain
|
|
171
|
+
* persistence via the `domain` option.
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```ts
|
|
175
|
+
* import { cookieAdapter } from '@tantainnovative/ndpr-toolkit/adapters';
|
|
176
|
+
* import { useConsent } from '@tantainnovative/ndpr-toolkit/hooks';
|
|
177
|
+
*
|
|
178
|
+
* const adapter = cookieAdapter('ndpr_consent', {
|
|
179
|
+
* domain: '.example.com',
|
|
180
|
+
* sameSite: 'Lax',
|
|
181
|
+
* expires: 180,
|
|
182
|
+
* });
|
|
183
|
+
* useConsent({ options, adapter });
|
|
184
|
+
* ```
|
|
185
|
+
*/
|
|
143
186
|
export declare function cookieAdapter<T = unknown>(key: string, options?: CookieAdapterOptions): StorageAdapter<T>;
|
|
144
187
|
|
|
145
188
|
export declare interface CookieAdapterOptions {
|
|
@@ -150,10 +193,53 @@ export declare interface CookieAdapterOptions {
|
|
|
150
193
|
sameSite?: 'Strict' | 'Lax' | 'None';
|
|
151
194
|
}
|
|
152
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Storage adapter backed by `window.localStorage`. The default adapter used
|
|
198
|
+
* by every hook in the toolkit when no `adapter` prop is supplied.
|
|
199
|
+
*
|
|
200
|
+
* Safe to import server-side — every method short-circuits when
|
|
201
|
+
* `window` is undefined, so calling `load()` on the server returns `null`.
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* ```ts
|
|
205
|
+
* import { localStorageAdapter } from '@tantainnovative/ndpr-toolkit/adapters';
|
|
206
|
+
* import { useConsent } from '@tantainnovative/ndpr-toolkit/hooks';
|
|
207
|
+
*
|
|
208
|
+
* const adapter = localStorageAdapter('ndpr_consent');
|
|
209
|
+
* useConsent({ options, adapter });
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
153
212
|
export declare function localStorageAdapter<T = unknown>(key: string): StorageAdapter<T>;
|
|
154
213
|
|
|
214
|
+
/**
|
|
215
|
+
* Storage adapter backed by an in-memory value. Useful in tests, Storybook,
|
|
216
|
+
* SSR previews, or anywhere persistence across reloads is undesirable.
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* ```ts
|
|
220
|
+
* import { memoryAdapter } from '@tantainnovative/ndpr-toolkit/adapters';
|
|
221
|
+
* import { useConsent } from '@tantainnovative/ndpr-toolkit/hooks';
|
|
222
|
+
*
|
|
223
|
+
* const adapter = memoryAdapter({ consents: {}, version: '1.0' });
|
|
224
|
+
* useConsent({ options, adapter });
|
|
225
|
+
* ```
|
|
226
|
+
*/
|
|
155
227
|
export declare function memoryAdapter<T = unknown>(initialData?: T): StorageAdapter<T>;
|
|
156
228
|
|
|
229
|
+
/**
|
|
230
|
+
* Storage adapter backed by `window.sessionStorage`. Data is scoped to the
|
|
231
|
+
* current tab and discarded when the tab closes — useful for consent
|
|
232
|
+
* choices that should not survive a fresh session.
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```ts
|
|
236
|
+
* import { sessionStorageAdapter } from '@tantainnovative/ndpr-toolkit/adapters';
|
|
237
|
+
* import { useConsent } from '@tantainnovative/ndpr-toolkit/hooks';
|
|
238
|
+
*
|
|
239
|
+
* const adapter = sessionStorageAdapter('ndpr_consent');
|
|
240
|
+
* useConsent({ options, adapter });
|
|
241
|
+
* ```
|
|
242
|
+
*/
|
|
157
243
|
export declare function sessionStorageAdapter<T = unknown>(key: string): StorageAdapter<T>;
|
|
158
244
|
|
|
159
245
|
export declare interface StorageAdapter<T = unknown> {
|
package/dist/breach.d.mts
CHANGED
|
@@ -770,7 +770,19 @@ export declare interface StorageAdapter<T = unknown> {
|
|
|
770
770
|
}
|
|
771
771
|
|
|
772
772
|
/**
|
|
773
|
-
* Hook for managing data breach notifications in compliance with the NDPA (Section 40)
|
|
773
|
+
* Hook for managing data breach notifications in compliance with the NDPA (Section 40).
|
|
774
|
+
*
|
|
775
|
+
* @example
|
|
776
|
+
* ```tsx
|
|
777
|
+
* import { useBreach } from '@tantainnovative/ndpr-toolkit/hooks';
|
|
778
|
+
*
|
|
779
|
+
* function BreachConsole() {
|
|
780
|
+
* const { reports, reportBreach } = useBreach({
|
|
781
|
+
* categories: [{ id: 'unauthorized-access', name: 'Unauthorised access', description: '' }],
|
|
782
|
+
* });
|
|
783
|
+
* return <p>{reports.length} breach report(s) on record.</p>;
|
|
784
|
+
* }
|
|
785
|
+
* ```
|
|
774
786
|
*/
|
|
775
787
|
export declare function useBreach({ categories, initialReports, adapter, storageKey, useLocalStorage, onReport, onAssessment, onNotification, }: UseBreachOptions): UseBreachReturn;
|
|
776
788
|
|
package/dist/breach.d.ts
CHANGED
|
@@ -770,7 +770,19 @@ export declare interface StorageAdapter<T = unknown> {
|
|
|
770
770
|
}
|
|
771
771
|
|
|
772
772
|
/**
|
|
773
|
-
* Hook for managing data breach notifications in compliance with the NDPA (Section 40)
|
|
773
|
+
* Hook for managing data breach notifications in compliance with the NDPA (Section 40).
|
|
774
|
+
*
|
|
775
|
+
* @example
|
|
776
|
+
* ```tsx
|
|
777
|
+
* import { useBreach } from '@tantainnovative/ndpr-toolkit/hooks';
|
|
778
|
+
*
|
|
779
|
+
* function BreachConsole() {
|
|
780
|
+
* const { reports, reportBreach } = useBreach({
|
|
781
|
+
* categories: [{ id: 'unauthorized-access', name: 'Unauthorised access', description: '' }],
|
|
782
|
+
* });
|
|
783
|
+
* return <p>{reports.length} breach report(s) on record.</p>;
|
|
784
|
+
* }
|
|
785
|
+
* ```
|
|
774
786
|
*/
|
|
775
787
|
export declare function useBreach({ categories, initialReports, adapter, storageKey, useLocalStorage, onReport, onAssessment, onNotification, }: UseBreachOptions): UseBreachReturn;
|
|
776
788
|
|
package/dist/breach.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
'use strict';var
|
|
2
|
+
'use strict';var chunkYK22SYCT_js=require('./chunk-YK22SYCT.js'),chunkVUFTRKKC_js=require('./chunk-VUFTRKKC.js'),chunkEHQVTFYO_js=require('./chunk-EHQVTFYO.js'),chunk3YTAOT5O_js=require('./chunk-3YTAOT5O.js');require('./chunk-UXUMYP4L.js'),require('./chunk-NDKDKDDX.js'),require('./chunk-WKTKTLMF.js'),require('./chunk-ZVOIR4QH.js'),require('./chunk-AME4HJR4.js'),require('./chunk-VWED6UTN.js');var chunkRFPLZDIO_js=require('./chunk-RFPLZDIO.js'),react=require('react'),jsxRuntime=require('react/jsx-runtime');var c=react.createContext(null);function P(){let e=react.useContext(c);if(!e)throw new Error("Breach compound components must be wrapped in <Breach.Provider>. Example: <Breach.Provider categories={...}><Breach.ReportForm /></Breach.Provider>");return e}var p=({categories:e,adapter:m,storageKey:h,useLocalStorage:B,initialReports:f,onReport:R,onAssessment:x,onNotification:u,children:d})=>{let y=chunkEHQVTFYO_js.a({categories:e,adapter:m,storageKey:h,useLocalStorage:B,initialReports:f,onReport:R,onAssessment:x,onNotification:u}),l=chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a({},y),{categories:e});return jsxRuntime.jsx(c.Provider,{value:l,children:d})};var A={Provider:p,ReportForm:chunkVUFTRKKC_js.a,RiskAssessment:chunkYK22SYCT_js.a,NotificationManager:chunkYK22SYCT_js.b,ReportGenerator:chunkYK22SYCT_js.c};Object.defineProperty(exports,"BreachNotificationManager",{enumerable:true,get:function(){return chunkYK22SYCT_js.b}});Object.defineProperty(exports,"BreachRiskAssessment",{enumerable:true,get:function(){return chunkYK22SYCT_js.a}});Object.defineProperty(exports,"RegulatoryReportGenerator",{enumerable:true,get:function(){return chunkYK22SYCT_js.c}});Object.defineProperty(exports,"BreachReportForm",{enumerable:true,get:function(){return chunkVUFTRKKC_js.a}});Object.defineProperty(exports,"useBreach",{enumerable:true,get:function(){return chunkEHQVTFYO_js.a}});Object.defineProperty(exports,"calculateBreachSeverity",{enumerable:true,get:function(){return chunk3YTAOT5O_js.a}});exports.Breach=A;exports.BreachProvider=p;exports.useBreachCompound=P;
|
package/dist/breach.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {c as c$1,b,a}from'./chunk-
|
|
2
|
+
import {c as c$1,b,a}from'./chunk-JYZOKO2W.mjs';export{b as BreachNotificationManager,a as BreachRiskAssessment,c as RegulatoryReportGenerator}from'./chunk-JYZOKO2W.mjs';import {a as a$1}from'./chunk-TN4TH3CT.mjs';export{a as BreachReportForm}from'./chunk-TN4TH3CT.mjs';import {a as a$2}from'./chunk-RFXGD5NE.mjs';export{a as useBreach}from'./chunk-RFXGD5NE.mjs';export{a as calculateBreachSeverity}from'./chunk-WTGKZX7J.mjs';import'./chunk-EWVK45Z3.mjs';import'./chunk-25TNTLHJ.mjs';import'./chunk-RBMLGRDN.mjs';import'./chunk-ITCY2Z66.mjs';import'./chunk-SFGW37LE.mjs';import'./chunk-DBZSN4WP.mjs';import {b as b$1,a as a$3}from'./chunk-ZJYULEER.mjs';import {createContext,useContext}from'react';import {jsx}from'react/jsx-runtime';var c=createContext(null);function P(){let e=useContext(c);if(!e)throw new Error("Breach compound components must be wrapped in <Breach.Provider>. Example: <Breach.Provider categories={...}><Breach.ReportForm /></Breach.Provider>");return e}var p=({categories:e,adapter:m,storageKey:h,useLocalStorage:B,initialReports:f,onReport:R,onAssessment:x,onNotification:u,children:d})=>{let y=a$2({categories:e,adapter:m,storageKey:h,useLocalStorage:B,initialReports:f,onReport:R,onAssessment:x,onNotification:u}),l=b$1(a$3({},y),{categories:e});return jsx(c.Provider,{value:l,children:d})};var A={Provider:p,ReportForm:a$1,RiskAssessment:a,NotificationManager:b,ReportGenerator:c$1};export{A as Breach,p as BreachProvider,P as useBreachCompound};
|