@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.
Files changed (103) hide show
  1. package/CHANGELOG.md +111 -0
  2. package/README.md +38 -24
  3. package/dist/adapters.d.mts +90 -4
  4. package/dist/adapters.d.ts +90 -4
  5. package/dist/breach.d.mts +13 -1
  6. package/dist/breach.d.ts +13 -1
  7. package/dist/breach.js +1 -1
  8. package/dist/breach.mjs +1 -1
  9. package/dist/{chunk-EZCGTHQV.js → chunk-4GIMXUMI.js} +3 -3
  10. package/dist/{chunk-HBLGN4SD.js → chunk-5AECGMEB.js} +1 -1
  11. package/dist/chunk-67KA345Q.mjs +1 -0
  12. package/dist/chunk-6OWCUDTN.mjs +1 -0
  13. package/dist/{chunk-4G3SRVRI.mjs → chunk-B6BRD5SL.mjs} +1 -1
  14. package/dist/chunk-CAFCRCTZ.mjs +1 -0
  15. package/dist/{chunk-VJTQXVAF.js → chunk-EHQVTFYO.js} +1 -1
  16. package/dist/{chunk-CNM6G5IA.js → chunk-FC3PTJFL.js} +1 -1
  17. package/dist/{chunk-H3IULCE3.js → chunk-HOAC5VUF.js} +1 -1
  18. package/dist/{chunk-H3XJV2IR.mjs → chunk-I3V3ITN7.mjs} +1 -1
  19. package/dist/{chunk-MPBPAEZC.mjs → chunk-IB3KSUPZ.mjs} +1 -1
  20. package/dist/{chunk-TAHSSITO.mjs → chunk-IHNAFXDM.mjs} +1 -1
  21. package/dist/chunk-IQO3SIAG.mjs +1 -0
  22. package/dist/{chunk-UTFBKL73.js → chunk-IRRUYR6M.js} +1 -1
  23. package/dist/{chunk-C7IDR2IV.js → chunk-JLQT3W3E.js} +1 -1
  24. package/dist/chunk-JYZOKO2W.mjs +103 -0
  25. package/dist/chunk-NX5MOBRI.js +1 -0
  26. package/dist/chunk-O2WEABB3.js +1 -0
  27. package/dist/chunk-OZHUINWS.js +1 -0
  28. package/dist/{chunk-66NQ5CVY.mjs → chunk-Q4CSVWSS.mjs} +1 -1
  29. package/dist/{chunk-CR2QZTGW.js → chunk-QMAVEHOR.js} +1 -1
  30. package/dist/{chunk-3HOXQNCH.mjs → chunk-RFXGD5NE.mjs} +1 -1
  31. package/dist/chunk-ROC64RLP.js +1 -0
  32. package/dist/{chunk-O45PKBZA.mjs → chunk-RR3KXNET.mjs} +3 -3
  33. package/dist/{chunk-KY6WYHWB.mjs → chunk-TN4TH3CT.mjs} +1 -1
  34. package/dist/chunk-VPNK7OID.mjs +1 -0
  35. package/dist/{chunk-O2RDZGM2.js → chunk-VUFTRKKC.js} +1 -1
  36. package/dist/chunk-WKUC65HL.mjs +1 -0
  37. package/dist/chunk-WXUXCRAJ.js +1 -0
  38. package/dist/chunk-YK22SYCT.js +103 -0
  39. package/dist/chunk-YSD2DFBR.js +6 -0
  40. package/dist/chunk-ZHX62QAL.mjs +6 -0
  41. package/dist/consent.d.mts +23 -1
  42. package/dist/consent.d.ts +23 -1
  43. package/dist/consent.js +1 -1
  44. package/dist/consent.mjs +1 -1
  45. package/dist/core.js +1 -1
  46. package/dist/core.mjs +1 -1
  47. package/dist/cross-border.d.mts +12 -1
  48. package/dist/cross-border.d.ts +12 -1
  49. package/dist/cross-border.js +1 -1
  50. package/dist/cross-border.mjs +1 -1
  51. package/dist/dpia.d.mts +16 -1
  52. package/dist/dpia.d.ts +16 -1
  53. package/dist/dpia.js +1 -1
  54. package/dist/dpia.mjs +1 -1
  55. package/dist/dsr.d.mts +21 -1
  56. package/dist/dsr.d.ts +21 -1
  57. package/dist/dsr.js +1 -1
  58. package/dist/dsr.mjs +1 -1
  59. package/dist/headless.d.mts +217 -24
  60. package/dist/headless.d.ts +217 -24
  61. package/dist/headless.js +1 -1
  62. package/dist/headless.mjs +1 -1
  63. package/dist/hooks.d.mts +217 -24
  64. package/dist/hooks.d.ts +217 -24
  65. package/dist/hooks.js +1 -1
  66. package/dist/hooks.mjs +1 -1
  67. package/dist/index.d.mts +419 -29
  68. package/dist/index.d.ts +419 -29
  69. package/dist/index.js +1 -1
  70. package/dist/index.mjs +1 -1
  71. package/dist/lawful-basis.d.mts +10 -0
  72. package/dist/lawful-basis.d.ts +10 -0
  73. package/dist/lawful-basis.js +1 -1
  74. package/dist/lawful-basis.mjs +1 -1
  75. package/dist/policy.d.mts +39 -1
  76. package/dist/policy.d.ts +39 -1
  77. package/dist/presets.js +1 -1
  78. package/dist/presets.mjs +1 -1
  79. package/dist/ropa.d.mts +39 -3
  80. package/dist/ropa.d.ts +39 -3
  81. package/dist/ropa.js +1 -1
  82. package/dist/ropa.mjs +1 -1
  83. package/dist/server.d.mts +86 -0
  84. package/dist/server.d.ts +86 -0
  85. package/dist/server.js +1 -1
  86. package/dist/server.mjs +1 -1
  87. package/dist/styles.css +2 -0
  88. package/package.json +1 -1
  89. package/dist/chunk-3JPDTXGC.js +0 -1
  90. package/dist/chunk-43OQNS2J.mjs +0 -6
  91. package/dist/chunk-5GVMKUMP.js +0 -1
  92. package/dist/chunk-COD3RMTL.mjs +0 -1
  93. package/dist/chunk-EXEXUAF6.mjs +0 -1
  94. package/dist/chunk-L2BRFMVS.js +0 -1
  95. package/dist/chunk-MOHBL6LX.mjs +0 -1
  96. package/dist/chunk-PGI2LM6P.js +0 -103
  97. package/dist/chunk-PZRQWPWD.js +0 -1
  98. package/dist/chunk-RPXRPGHL.mjs +0 -1
  99. package/dist/chunk-RZ6GC6WN.mjs +0 -1
  100. package/dist/chunk-SSH4U4TJ.js +0 -6
  101. package/dist/chunk-WDDCKYWA.js +0 -1
  102. package/dist/chunk-X3GCGC3H.mjs +0 -103
  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.10.3 Release](https://github.com/mr-tanta/ndpr-toolkit/releases/tag/v3.10.3)**
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
  [![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.10.x:** Typed theming via `<NDPRThemeProvider>`, a `/headless` subpath alias of `/hooks` for headless-UI consumers, and a production-grade DSR backend reference at `examples/dsr-backend-prod/` (Prisma + Resend behind no-infra shims). New docs guides: [theming](https://ndprtoolkit.com.ng/docs/guides/theming), [headless](https://ndprtoolkit.com.ng/docs/guides/headless), [production-dsr-backend](https://ndprtoolkit.com.ng/docs/guides/production-dsr-backend).
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?** See the [3.7 → 3.10 upgrade guide](https://ndprtoolkit.com.ng/docs/guides/upgrading-3-7-to-3-10) — fully additive, no API breaks. Full changelog on [GitHub](https://github.com/mr-tanta/ndpr-toolkit/blob/main/CHANGELOG.md).
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.10.3/public/screenshots/hero.png" alt="NDPA Toolkit — NDPA Compliance Made Beautiful" width="800" />
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
- ## The 3-File Quickstart
29
+ ## Quickstart
30
30
 
31
- Three files. Full NDPA consent compliance.
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
- **`app/api/consent/route.ts`**
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
- export async function GET() { return NextResponse.json(store ?? {}); }
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
- That's it. NDPA-compliant consent with server-side persistence in under 20 lines.
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.10.3/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/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.10.3/public/screenshots/demos-overview.png" alt="8 interactive live demos — zero setup required" width="800" />
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.10.3/public/screenshots/dsr-demo.png" alt="Data Subject Rights — 8 rights with request tracking" width="400" />
443
- <img src="https://raw.githubusercontent.com/mr-tanta/ndpr-toolkit/v3.10.3/public/screenshots/breach-demo.png" alt="Breach Notification — 72-hour countdown with step-by-step workflow" width="400" />
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">
@@ -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> {
@@ -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 chunkPGI2LM6P_js=require('./chunk-PGI2LM6P.js'),chunkO2RDZGM2_js=require('./chunk-O2RDZGM2.js'),chunkVJTQXVAF_js=require('./chunk-VJTQXVAF.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=chunkVJTQXVAF_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:chunkO2RDZGM2_js.a,RiskAssessment:chunkPGI2LM6P_js.a,NotificationManager:chunkPGI2LM6P_js.b,ReportGenerator:chunkPGI2LM6P_js.c};Object.defineProperty(exports,"BreachNotificationManager",{enumerable:true,get:function(){return chunkPGI2LM6P_js.b}});Object.defineProperty(exports,"BreachRiskAssessment",{enumerable:true,get:function(){return chunkPGI2LM6P_js.a}});Object.defineProperty(exports,"RegulatoryReportGenerator",{enumerable:true,get:function(){return chunkPGI2LM6P_js.c}});Object.defineProperty(exports,"BreachReportForm",{enumerable:true,get:function(){return chunkO2RDZGM2_js.a}});Object.defineProperty(exports,"useBreach",{enumerable:true,get:function(){return chunkVJTQXVAF_js.a}});Object.defineProperty(exports,"calculateBreachSeverity",{enumerable:true,get:function(){return chunk3YTAOT5O_js.a}});exports.Breach=A;exports.BreachProvider=p;exports.useBreachCompound=P;
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-X3GCGC3H.mjs';export{b as BreachNotificationManager,a as BreachRiskAssessment,c as RegulatoryReportGenerator}from'./chunk-X3GCGC3H.mjs';import {a as a$1}from'./chunk-KY6WYHWB.mjs';export{a as BreachReportForm}from'./chunk-KY6WYHWB.mjs';import {a as a$2}from'./chunk-3HOXQNCH.mjs';export{a as useBreach}from'./chunk-3HOXQNCH.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};
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};