@tantainnovative/ndpr-toolkit 3.7.0 → 3.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +200 -0
- package/README.md +146 -1
- package/dist/{chunk-SJRIOZ4K.mjs → chunk-EFIWANHF.mjs} +1 -1
- package/dist/chunk-GQYBS3A7.mjs +0 -0
- package/dist/chunk-OZCNFB5C.js +1 -0
- package/dist/{chunk-RXZFYBUJ.js → chunk-XS3Z4UT7.js} +1 -1
- package/dist/core.js +1 -1
- package/dist/core.mjs +1 -1
- package/dist/cross-border-lite.d.mts +141 -0
- package/dist/cross-border-lite.d.ts +141 -0
- package/dist/cross-border-lite.js +2 -0
- package/dist/cross-border-lite.mjs +2 -0
- package/dist/dsr.js +1 -1
- package/dist/dsr.mjs +1 -1
- package/dist/headless.d.mts +2391 -0
- package/dist/headless.d.ts +2391 -0
- package/dist/headless.js +2 -0
- package/dist/headless.mjs +2 -0
- package/dist/hooks.js +1 -1
- package/dist/hooks.mjs +1 -1
- package/dist/index.d.mts +123 -0
- package/dist/index.d.ts +123 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/lawful-basis-lite.d.mts +153 -0
- package/dist/lawful-basis-lite.d.ts +153 -0
- package/dist/lawful-basis-lite.js +2 -0
- package/dist/lawful-basis-lite.mjs +2 -0
- package/dist/presets-dsr.d.mts +25 -0
- package/dist/presets-dsr.d.ts +25 -0
- package/dist/presets-dsr.js +1 -1
- package/dist/presets-dsr.mjs +1 -1
- package/dist/presets.d.mts +25 -0
- package/dist/presets.d.ts +25 -0
- package/dist/presets.js +1 -1
- package/dist/presets.mjs +1 -1
- package/dist/ropa-lite.d.mts +218 -0
- package/dist/ropa-lite.d.ts +218 -0
- package/dist/ropa-lite.js +2 -0
- package/dist/ropa-lite.mjs +2 -0
- package/dist/server.js +1 -1
- package/dist/server.mjs +1 -1
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,206 @@
|
|
|
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.10.1](https://github.com/mr-tanta/ndpr-toolkit/compare/v3.10.0...v3.10.1) (2026-05-25)
|
|
6
|
+
|
|
7
|
+
Hotfix release. Code and runtime are identical to 3.10.0 — this patch fixes the build/publish pipeline that silently failed every release from 3.8.0 onward, so 3.10.1 is the first version since 3.7.0 to actually reach npm.
|
|
8
|
+
|
|
9
|
+
### Root cause
|
|
10
|
+
|
|
11
|
+
The dts-rollup post-build step (`scripts/rollup-dts.mjs`) deletes "leftover" hash-suffixed declaration files that tsup emits alongside each rolled-up entry. The 3.8.0 release added new entry names with two hyphens (`lawful-basis-lite`, `cross-border-lite`) — and the hash-suffix regex `/-[A-Za-z0-9_-]{8,}\.d\.m?ts$/` matched those legitimate entries because the trailing `basis-lite` / `border-lite` segments fall inside the 8-char dash-inclusive window. The sweep then deleted `dist/lawful-basis-lite.d.ts` and `dist/cross-border-lite.d.ts` right after rollup, the workflow's entry-points check then failed, and `npm publish` never ran. The git tags / GitHub releases for 3.8.0, 3.8.1, 3.9.0, and 3.10.0 existed; only npm was stuck on 3.7.0.
|
|
12
|
+
|
|
13
|
+
### Fix
|
|
14
|
+
|
|
15
|
+
- Replaced the regex-based sweep with an explicit allowlist (`new Set([...ENTRIES, 'styles'])`). Any `.d.ts` / `.d.mts` whose basename isn't in the allowed entries gets swept. No more pattern matching against names.
|
|
16
|
+
- Wired the 3.10.0 `/headless` entry into the root `tsup.config.ts` (it had only been wired in `packages/ndpr-toolkit/tsup.config.ts`, which the publish workflow doesn't use) and added it to `CLIENT_ENTRIES` so the `"use client"` banner is injected.
|
|
17
|
+
- Workflow's `Verify entry points` step now covers 22 entries (was 21) — added `headless`.
|
|
18
|
+
|
|
19
|
+
### Recovery
|
|
20
|
+
|
|
21
|
+
After this patch lands and 3.10.1 publishes successfully, the failed tags (v3.8.0, v3.8.1, v3.9.0, v3.10.0) will be backfilled to npm by cherry-picking this fix onto each tagged commit and re-running the workflow.
|
|
22
|
+
|
|
23
|
+
## [3.10.0](https://github.com/mr-tanta/ndpr-toolkit/compare/v3.9.0...v3.10.0) (2026-05-25)
|
|
24
|
+
|
|
25
|
+
Phase J of the feedback work — new API surface (theme provider + headless alias) and a production-grade DSR backend reference. Fully additive — no breaking changes.
|
|
26
|
+
|
|
27
|
+
### `NDPRThemeProvider` — typed theme object → CSS variables
|
|
28
|
+
|
|
29
|
+
A small React Context provider that takes a TypeScript theme object and injects matching `--ndpr-*` CSS custom properties on a wrapping `div`. Syntactic sugar over the existing CSS-variable theming model — unset fields fall through to stylesheet defaults.
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import { NDPRThemeProvider, type NDPRTheme } from '@tantainnovative/ndpr-toolkit';
|
|
33
|
+
|
|
34
|
+
const theme: NDPRTheme = {
|
|
35
|
+
colors: { primary: '22 163 74', primaryHover: '21 128 61' }, // RGB triplets
|
|
36
|
+
radius: { base: '0.75rem' },
|
|
37
|
+
font: { sans: '"Inter", system-ui, sans-serif' },
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
<NDPRThemeProvider theme={theme}>
|
|
41
|
+
<App />
|
|
42
|
+
</NDPRThemeProvider>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The `NDPRTheme` interface keys are derived 1:1 from the variables actually defined in `styles.css` — no inventing tokens. Setting `mode: 'dark'` stamps `data-theme="dark"` on the wrapper to activate the stylesheet's dark-mode block. **6 new tests** cover variable injection, key isolation, dark-mode wiring, and className passthrough. Exported from the default entry only (not `/core`) to keep the RSC-safe surface clean.
|
|
46
|
+
|
|
47
|
+
### `/headless` subpath — alias of `/hooks` for discoverability
|
|
48
|
+
|
|
49
|
+
A pure rename of the existing `/hooks` entry under a more discoverable name. Same exports, same source, same identifiers — `export *` from `hooks-entry.ts`. Useful when consumers grep for "headless" looking for a hooks-only API.
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
import { useConsent, useDSR, useFocusTrap } from '@tantainnovative/ndpr-toolkit/headless';
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**12 new tests** verify that `/headless` and `/hooks` export identical keys and identity-equal values (so the alias can never silently drift). Wired into `package.json` exports, `typesVersions`, and `tsup.config.ts`.
|
|
56
|
+
|
|
57
|
+
### `examples/dsr-backend-prod/` — production-grade DSR backend
|
|
58
|
+
|
|
59
|
+
A 14-file Next.js 15 / React 19 reference implementation that wires `NDPRSubjectRights` to a real backend pipeline:
|
|
60
|
+
|
|
61
|
+
1. **Validate** via `validateDsrSubmission` from `/server` — 400 with `{ error, fields }` on invalid payloads.
|
|
62
|
+
2. **Defense-in-depth** disposable-email blocklist (configurable via `DSR_BLOCKED_EMAIL_DOMAINS`).
|
|
63
|
+
3. **Persist** to a Prisma `DSRRequest` model with a 30-day `estimatedCompletionAt` (NDPA Part IV §29-36).
|
|
64
|
+
4. **Confirm** by sending a Resend transactional email — best-effort: the request still succeeds if email fails.
|
|
65
|
+
|
|
66
|
+
Both Prisma and Resend are wrapped in **dual-mode shims**: real clients when `DATABASE_URL` / `RESEND_API_KEY` are set, otherwise a Map-backed mock and a stdout logger. The example runs out of the box with no infrastructure.
|
|
67
|
+
|
|
68
|
+
The 201 response is exactly `{ referenceId, status, estimatedCompletionAt }` — the shape `NDPRSubjectRights.onSubmitSuccess` consumers read from `body` per the 3.8.1 contract.
|
|
69
|
+
|
|
70
|
+
### Three new docs guides
|
|
71
|
+
|
|
72
|
+
Wired into the Implementation Guides sidebar:
|
|
73
|
+
|
|
74
|
+
- `/docs/guides/theming` — `NDPRThemeProvider`, the full `NDPRTheme` reference, RGB-triplet convention, dark mode, when not to use the provider
|
|
75
|
+
- `/docs/guides/headless` — `/headless` quickstart, the 10 hooks it exposes, adapter wiring, bundle-size note, the relationship to `/hooks`
|
|
76
|
+
- `/docs/guides/production-dsr-backend` — walks through the `examples/dsr-backend-prod` pipeline, response contract, and how to swap in your own database/email stack
|
|
77
|
+
|
|
78
|
+
### Verification
|
|
79
|
+
|
|
80
|
+
- `tsc --noEmit` clean for the docs site
|
|
81
|
+
- **Full Jest suite: 1192/1192 passing** (was 1173 — +19: 6 ThemeProvider + 12 headless-parity + 1 default-entry exports check)
|
|
82
|
+
- No changes to existing prop types, hook signatures, or storage adapters
|
|
83
|
+
|
|
84
|
+
## [3.9.0](https://github.com/mr-tanta/ndpr-toolkit/compare/v3.8.1...v3.9.0) (2026-05-25)
|
|
85
|
+
|
|
86
|
+
Examples expansion + Bun quickstart + SSR-safe storage docs. Fully additive — no breaking changes.
|
|
87
|
+
|
|
88
|
+
### Runnable example apps
|
|
89
|
+
|
|
90
|
+
- **`examples/ecommerce-starter`** — multi-page Next.js 15 / React 19 storefront ("Zuri Market") wiring the toolkit into a realistic Nigerian ecommerce flow: home page, checkout, privacy notice, data-subject rights portal (with `submitTo` + `onSubmitSuccess` rendering a server-issued reference), and an editable cookie preferences page using `useConsent`. Demonstrates the `/presets/consent`, `/presets/dsr`, `/presets/policy`, and `/hooks` subpaths together.
|
|
91
|
+
- **`examples/ssr/nextjs-app-router`** — SSR-safe consent on Next.js 15. Layout reads the consent cookie via `next/headers`, parses it with a small typed helper, and passes the result to a client `ConsentRoot` so the banner hydrates already-resolved (no flash, no hydration warning).
|
|
92
|
+
- **`examples/ssr/remix`** — the same cookie-bridge pattern wired from a Remix `loader` and Vite's `?url` asset import for the stylesheet.
|
|
93
|
+
- **`examples/ssr/astro`** — `Astro.cookies.get` in the page frontmatter, then `<ConsentRoot client:load>` as a React island.
|
|
94
|
+
|
|
95
|
+
Each example is self-contained (own `package.json`, `tsconfig.json`, `next.config.mjs` / `vite.config.ts` / `astro.config.mjs`) so you can copy a directory and `bun install && bun dev` to run it.
|
|
96
|
+
|
|
97
|
+
### Bun quickstart in the README
|
|
98
|
+
|
|
99
|
+
Root README now includes copy-pasteable Bun + Vite + React and Bun + Next.js 15 (App Router) recipes that go from zero to a working banner in three commands. The npm-published README also gets a one-line Bun install command alongside pnpm/npm.
|
|
100
|
+
|
|
101
|
+
### SSR-safe storage guide
|
|
102
|
+
|
|
103
|
+
New docs page at **`/docs/guides/server-side-storage`** documenting the cookie-bridge pattern in detail: why `localStorageAdapter` flashes on SSR, how `cookieAdapter` solves it, and worked examples for Next.js App Router, Remix, Astro, and SvelteKit. Wired into the docs sidebar under Implementation Guides.
|
|
104
|
+
|
|
105
|
+
### npm-published README brought current (3.4.0 → 3.9.0)
|
|
106
|
+
|
|
107
|
+
The README that ships to npm was stale at the 3.4.0 highlights. It now leads with a 3.9.0 "what's new", references back to 3.8.1 (`onSubmitSuccess`), 3.8.0 (Lite Manager variants), 3.6.0 (`onSubmitError`), and 3.5.x (focus management + reduced motion). Adds a "Runnable Examples" section, a typed DSR callbacks snippet in the Presets section, and a Bun install command. Screenshot URLs bumped from `v3.5.2` → `v3.9.0`. Tests badge bumped to 1173.
|
|
108
|
+
|
|
109
|
+
### Verification
|
|
110
|
+
|
|
111
|
+
- `tsc --noEmit` clean for the docs site
|
|
112
|
+
- **Full Jest suite: 1173/1173 passing** (unchanged from 3.8.1 — no logic changes in the published package)
|
|
113
|
+
- No changes to runtime exports, prop types, or storage adapters
|
|
114
|
+
|
|
115
|
+
## [3.8.1](https://github.com/mr-tanta/ndpr-toolkit/compare/v3.8.0...v3.8.1) (2026-05-25)
|
|
116
|
+
|
|
117
|
+
Documentation + small API addition patch. Fully additive — no breaking changes.
|
|
118
|
+
|
|
119
|
+
### `NDPRSubjectRights` — typed `onSubmitSuccess` callback
|
|
120
|
+
|
|
121
|
+
Counterpart to the existing `onSubmitError`. Fires when the `submitTo` POST returns a 2xx response. Receives the `Response`, the submitted `DSRFormSubmission` payload, and the parsed JSON body (or `undefined` if the response had no body or was not valid JSON).
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
<NDPRSubjectRights
|
|
125
|
+
submitTo="/api/dsr"
|
|
126
|
+
onSubmitSuccess={({ response, data, body }) => {
|
|
127
|
+
const ref = (body as { referenceId?: string })?.referenceId;
|
|
128
|
+
if (ref) router.push(`/dsr-confirmation?ref=${ref}`);
|
|
129
|
+
}}
|
|
130
|
+
onSubmitError={({ error, response }) => {
|
|
131
|
+
console.error('DSR submit failed', error, response?.status);
|
|
132
|
+
}}
|
|
133
|
+
/>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
The `body` field is `unknown` to force consumers to narrow it themselves before reading fields. **4 new tests** cover both success and failure paths.
|
|
137
|
+
|
|
138
|
+
### Documentation
|
|
139
|
+
|
|
140
|
+
- **DSR submission payload contract** documented on the Data Subject Rights component page (`/docs/components/data-subject-rights#submission-payload`). Includes the canonical `DSRFormSubmission` TypeScript interface, a concrete JSON example, the recommended response shape, and a working Next.js App Router backend handler.
|
|
141
|
+
- **Accessibility sections** added to ConsentBanner and DSRRequestForm docs pages. Each lists CONCRETE a11y features verified against the source — `useFocusTrap`, escape-to-dismiss, `prefers-reduced-motion` block in the BEM stylesheet, `role="alert"` on errors, `aria-required` + `aria-invalid` wiring on form fields, etc. Features that aren't implemented (e.g. auto-focusing the first invalid field) are NOT claimed — they're suggested as consumer-side recipes instead.
|
|
142
|
+
- **Migration guide 3.5 → 3.8** at `/docs/guides/migrating-3-5-to-3-8`. Covers every minor and patch from 3.5.4 through 3.8.1 with a "what changed / action required" breakdown, a net migration diff for the most common upgrade path (adapter → submitTo + onSubmitSuccess), and a verify checklist. Sidebar entry added under Implementation Guides.
|
|
143
|
+
|
|
144
|
+
### Verification
|
|
145
|
+
|
|
146
|
+
- `tsc --noEmit` clean for both the library and the docs site
|
|
147
|
+
- **Full Jest suite: 1173/1173 passing** (was 1169 — +4 new submit-callback tests)
|
|
148
|
+
- No changes to the existing `onSubmitError`, `submitTo`, or `submitOptions` props (backward compatible)
|
|
149
|
+
|
|
150
|
+
## [3.8.0](https://github.com/mr-tanta/ndpr-toolkit/compare/v3.6.2...v3.8.0) (2026-05-24)
|
|
151
|
+
|
|
152
|
+
### Lite (read-only) variants of the heavy Manager components
|
|
153
|
+
|
|
154
|
+
Three new components — `LawfulBasisTrackerLite`, `ROPAManagerLite`, `CrossBorderTransferManagerLite` — that render the same list-and-summary view as their Full counterparts without the form, validation, write callbacks, or CSV-export utilities. Built for dashboards, audit pages, embedded compliance widgets, and customer-facing transparency pages where users only need to *see* the records.
|
|
155
|
+
|
|
156
|
+
Exposed at new subpath entries:
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
import { LawfulBasisTrackerLite } from '@tantainnovative/ndpr-toolkit/lawful-basis/lite';
|
|
160
|
+
import { ROPAManagerLite } from '@tantainnovative/ndpr-toolkit/ropa/lite';
|
|
161
|
+
import { CrossBorderTransferManagerLite } from '@tantainnovative/ndpr-toolkit/cross-border/lite';
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Bundle deltas (minified + tree-shaken, pre-gzip; **transitive closure** of each subpath):
|
|
165
|
+
|
|
166
|
+
| Module | Full | Lite | Saved |
|
|
167
|
+
|---|---|---|---|
|
|
168
|
+
| `/lawful-basis` → `/lawful-basis/lite` | 36.7 KB | 12.7 KB | **65%** |
|
|
169
|
+
| `/cross-border` → `/cross-border/lite` | 53.3 KB | 5.6 KB | **89%** |
|
|
170
|
+
| `/ropa` → `/ropa/lite` | 36.9 KB | 13.2 KB | **64%** |
|
|
171
|
+
|
|
172
|
+
The cross-border Lite saves the most because it does NOT import the 624-row country-adequacy dataset — Lite displays `adequacyStatus` from each transfer record directly instead of recomputing it.
|
|
173
|
+
|
|
174
|
+
Each Lite component accepts an optional `onActivityClick` / `onRecordClick` / `onTransferClick` callback so consumers can render their own detail view on row click. All other props (`title`, `description`, `unstyled`, `classNames`, `showSummary`, `showComplianceGaps`/`showRiskAlerts`) carry the same names and semantics as the Full versions.
|
|
175
|
+
|
|
176
|
+
Existing `/lawful-basis`, `/cross-border`, and `/ropa` entries are unchanged. This release is fully additive — no consumers need to migrate.
|
|
177
|
+
|
|
178
|
+
See the new guide: [Lite vs Full managers](https://ndprtoolkit.com.ng/docs/guides/lite-vs-full).
|
|
179
|
+
|
|
180
|
+
### Other
|
|
181
|
+
|
|
182
|
+
- Added `lawful-basis-lite`, `cross-border-lite`, `ropa-lite` to the publish workflow's entry-point verification loop. Total verified entries: 21.
|
|
183
|
+
|
|
184
|
+
## [3.6.2](https://github.com/mr-tanta/ndpr-toolkit/compare/v3.7.0...v3.6.2) (2026-05-24)
|
|
185
|
+
|
|
186
|
+
Compressed Phase D + E + F patch — companion-CLI templates, per-module StackBlitz scaffolds, and a real backend for the `/score` lead-magnet. Main `@tantainnovative/ndpr-toolkit` library has no code changes; the bump is for changelog alignment.
|
|
187
|
+
|
|
188
|
+
### Companion packages
|
|
189
|
+
|
|
190
|
+
- **`@tantainnovative/create-ndpr@0.3.0`** — the 9 remaining route templates now support all three ORM choices via `{{#if ORM=prisma|drizzle|none}}` conditional blocks. Picking `ORM=none` now scaffolds a fully working in-memory app for every endpoint, not just consent:
|
|
191
|
+
- Next.js routes: dsr, breach, dpia, lawful-basis, cross-border
|
|
192
|
+
- Express routes: consent, dpia, lawful-basis, cross-border
|
|
193
|
+
- **`create-ndpr@1.0.0` (unscoped alias)** — `packages/create-ndpr-unscoped/PUBLISHING.md` documents the one-time manual publish + Trusted Publisher setup so future updates flow through CI.
|
|
194
|
+
|
|
195
|
+
### Docs
|
|
196
|
+
|
|
197
|
+
- **8 per-module StackBlitz scaffolds** under `examples/stackblitz/{consent,dsr,dpia,breach,policy,lawful-basis,cross-border,ropa}/`. Each is a minimal Next.js 15 + React 19 app that demonstrates ONE preset. Boot any of them in StackBlitz / CodeSandbox with one click — no clone, no install. README has a per-module badge table.
|
|
198
|
+
- **Each recipe page** (`/docs/recipes/*`) now has "Open in StackBlitz" + "Open in CodeSandbox" badges pointing at the matching module's scaffold.
|
|
199
|
+
- **`/score` email capture** now uses a real backend (Web3Forms) when `NEXT_PUBLIC_WEB3FORMS_KEY` is set, with the mailto: path preserved as a graceful fallback when the env var is missing or the request fails. Lead emails arrive as structured fields (name, email, org, score, top recommendations) instead of free-form mail-client output.
|
|
200
|
+
|
|
201
|
+
### No library code changes
|
|
202
|
+
|
|
203
|
+
`@tantainnovative/ndpr-toolkit` package is unchanged; consumers don't need to upgrade. The version bump keeps the repo, npm, and CHANGELOG in lockstep so the next library feature (3.8.0 with manager-component bundle splitting) lands cleanly.
|
|
204
|
+
|
|
5
205
|
## [3.7.0](https://github.com/mr-tanta/ndpr-toolkit/compare/v3.6.1...v3.7.0) (2026-05-24)
|
|
6
206
|
|
|
7
207
|
Phase B — Template + Recipe Library. Closes the dev-feedback content gap (feedback items #7 and #9). New API additions are all backward-compatible — 3.6.x consumers upgrade without changes.
|
package/README.md
CHANGED
|
@@ -127,6 +127,101 @@ bun create ndpr
|
|
|
127
127
|
|
|
128
128
|
---
|
|
129
129
|
|
|
130
|
+
## Bun quickstart
|
|
131
|
+
|
|
132
|
+
Bun is a first-class runtime for the toolkit. Both common React app shapes work without extra config.
|
|
133
|
+
|
|
134
|
+
### Bun + Vite + React
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
bun create vite@latest my-ndpr-app --template react-ts
|
|
138
|
+
cd my-ndpr-app
|
|
139
|
+
bun install
|
|
140
|
+
bun add @tantainnovative/ndpr-toolkit
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
```tsx
|
|
144
|
+
// src/App.tsx
|
|
145
|
+
import { NDPRConsent } from '@tantainnovative/ndpr-toolkit/presets/consent';
|
|
146
|
+
import '@tantainnovative/ndpr-toolkit/styles';
|
|
147
|
+
|
|
148
|
+
export default function App() {
|
|
149
|
+
return (
|
|
150
|
+
<>
|
|
151
|
+
<NDPRConsent
|
|
152
|
+
options={[
|
|
153
|
+
{ id: 'essential', label: 'Essential', description: 'Required for the site to function', required: true, purpose: 'Site operation' },
|
|
154
|
+
{ id: 'analytics', label: 'Analytics', description: 'Anonymous usage measurement', required: false, purpose: 'Product analytics' },
|
|
155
|
+
{ id: 'marketing', label: 'Marketing', description: 'Personalised offers and ads', required: false, purpose: 'Marketing communications' },
|
|
156
|
+
]}
|
|
157
|
+
/>
|
|
158
|
+
<main className="p-6">
|
|
159
|
+
<h1 className="text-3xl font-semibold">My NDPA-compliant app</h1>
|
|
160
|
+
</main>
|
|
161
|
+
</>
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
bun dev
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Vite is client-only by default — no extra wiring needed. The toolkit's preset components ship with the `"use client"` directive already injected.
|
|
171
|
+
|
|
172
|
+
### Bun + Next.js 15 (App Router)
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
bun create next-app@latest my-ndpr-app --typescript --app --tailwind
|
|
176
|
+
cd my-ndpr-app
|
|
177
|
+
bun add @tantainnovative/ndpr-toolkit
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The consent banner is a stateful client component. Mount it from a small client wrapper so the rest of your layout can stay in RSC:
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
// app/ConsentRoot.tsx
|
|
184
|
+
'use client';
|
|
185
|
+
import { NDPRConsent } from '@tantainnovative/ndpr-toolkit/presets/consent';
|
|
186
|
+
|
|
187
|
+
export function ConsentRoot() {
|
|
188
|
+
return (
|
|
189
|
+
<NDPRConsent
|
|
190
|
+
options={[
|
|
191
|
+
{ id: 'essential', label: 'Essential', description: 'Required for the site to function', required: true, purpose: 'Site operation' },
|
|
192
|
+
{ id: 'analytics', label: 'Analytics', description: 'Anonymous usage measurement', required: false, purpose: 'Product analytics' },
|
|
193
|
+
{ id: 'marketing', label: 'Marketing', description: 'Personalised offers and ads', required: false, purpose: 'Marketing communications' },
|
|
194
|
+
]}
|
|
195
|
+
/>
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
```tsx
|
|
201
|
+
// app/layout.tsx
|
|
202
|
+
import '@tantainnovative/ndpr-toolkit/styles';
|
|
203
|
+
import { ConsentRoot } from './ConsentRoot';
|
|
204
|
+
|
|
205
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
206
|
+
return (
|
|
207
|
+
<html lang="en">
|
|
208
|
+
<body>
|
|
209
|
+
<ConsentRoot />
|
|
210
|
+
{children}
|
|
211
|
+
</body>
|
|
212
|
+
</html>
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
bun dev
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
You don't need to manually mark the import with `"use client"` from `app/layout.tsx` — the preset module already ships the directive in its bundled output, so React Server Components import it cleanly via the client wrapper. For RSC-safe, zero-React imports use `/server` or `/core` instead.
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
130
225
|
## Choose Your Layer
|
|
131
226
|
|
|
132
227
|
Pick exactly what your project needs.
|
|
@@ -350,6 +445,34 @@ Every module has an interactive demo. No signup, no setup — try them instantly
|
|
|
350
445
|
<em>Left: Data Subject Rights portal with 8 NDPA rights. Right: Breach notification with 72-hour NDPC deadline countdown.</em>
|
|
351
446
|
</p>
|
|
352
447
|
|
|
448
|
+
### Open any module in your browser (zero install)
|
|
449
|
+
|
|
450
|
+
Each module ships a minimal Next.js scaffold you can fork in StackBlitz or CodeSandbox. One click → working app demonstrating just that module:
|
|
451
|
+
|
|
452
|
+
| Module | NDPA | Open in StackBlitz | Open in CodeSandbox |
|
|
453
|
+
|---|---|---|---|
|
|
454
|
+
| **Ecommerce starter (full app)** | §25–27, §34–38 | [](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/ecommerce-starter) | [](https://codesandbox.io/p/github/mr-tanta/ndpr-toolkit/main/examples/ecommerce-starter) |
|
|
455
|
+
| Consent | §26 | [](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/stackblitz/consent) | [](https://codesandbox.io/p/github/mr-tanta/ndpr-toolkit/main/examples/stackblitz/consent) |
|
|
456
|
+
| DSR | §34 | [](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/stackblitz/dsr) | [](https://codesandbox.io/p/github/mr-tanta/ndpr-toolkit/main/examples/stackblitz/dsr) |
|
|
457
|
+
| DPIA | §28 | [](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/stackblitz/dpia) | [](https://codesandbox.io/p/github/mr-tanta/ndpr-toolkit/main/examples/stackblitz/dpia) |
|
|
458
|
+
| Breach | §40 | [](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/stackblitz/breach) | [](https://codesandbox.io/p/github/mr-tanta/ndpr-toolkit/main/examples/stackblitz/breach) |
|
|
459
|
+
| Policy | §27 | [](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/stackblitz/policy) | [](https://codesandbox.io/p/github/mr-tanta/ndpr-toolkit/main/examples/stackblitz/policy) |
|
|
460
|
+
| Lawful Basis | §25 | [](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/stackblitz/lawful-basis) | [](https://codesandbox.io/p/github/mr-tanta/ndpr-toolkit/main/examples/stackblitz/lawful-basis) |
|
|
461
|
+
| Cross-Border | §41–43 | [](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/stackblitz/cross-border) | [](https://codesandbox.io/p/github/mr-tanta/ndpr-toolkit/main/examples/stackblitz/cross-border) |
|
|
462
|
+
| RoPA | §29 | [](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/stackblitz/ropa) | [](https://codesandbox.io/p/github/mr-tanta/ndpr-toolkit/main/examples/stackblitz/ropa) |
|
|
463
|
+
|
|
464
|
+
Or open the [all-in-one example](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/nextjs-app) that demos every module in a single app.
|
|
465
|
+
|
|
466
|
+
### SSR-safe consent scaffolds
|
|
467
|
+
|
|
468
|
+
Cookie-bridged consent that hydrates without a flash. Each scaffold reads the `ndpr-consent` cookie on the server, seeds the banner's `show` prop, then lets the browser `cookieAdapter` take over. See the [Server-Side Storage guide](https://ndprtoolkit.com.ng/docs/guides/server-side-storage) for the pattern.
|
|
469
|
+
|
|
470
|
+
| Framework | Path | Open in StackBlitz |
|
|
471
|
+
|---|---|---|
|
|
472
|
+
| Next.js App Router | [`examples/ssr/nextjs-app-router`](./examples/ssr/nextjs-app-router) | [](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/ssr/nextjs-app-router) |
|
|
473
|
+
| Remix | [`examples/ssr/remix`](./examples/ssr/remix) | [](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/ssr/remix) |
|
|
474
|
+
| Astro | [`examples/ssr/astro`](./examples/ssr/astro) | [](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/ssr/astro) |
|
|
475
|
+
|
|
353
476
|
---
|
|
354
477
|
|
|
355
478
|
## All 8 Modules
|
|
@@ -390,7 +513,23 @@ import "@tantainnovative/ndpr-toolkit/styles";
|
|
|
390
513
|
}
|
|
391
514
|
```
|
|
392
515
|
|
|
393
|
-
|
|
516
|
+
**Theme via typed JS object — `NDPRThemeProvider` (new in 3.10.0):**
|
|
517
|
+
```tsx
|
|
518
|
+
import { NDPRThemeProvider, type NDPRTheme } from '@tantainnovative/ndpr-toolkit';
|
|
519
|
+
|
|
520
|
+
const theme: NDPRTheme = {
|
|
521
|
+
colors: { primary: '22 163 74', primaryHover: '21 128 61' },
|
|
522
|
+
radius: { base: '0.75rem' },
|
|
523
|
+
font: { sans: '"Inter", system-ui, sans-serif' },
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
<NDPRThemeProvider theme={theme}>
|
|
527
|
+
<App />
|
|
528
|
+
</NDPRThemeProvider>
|
|
529
|
+
```
|
|
530
|
+
The provider wraps children in a single `div` with the `--ndpr-*` variables set inline. Every `NDPRTheme` field is optional and maps 1:1 to a CSS variable defined in the stylesheet — unset fields fall through to defaults. Same end result as raw CSS overrides; pick what fits your codebase. Full reference in [the theming guide](https://ndprtoolkit.com.ng/docs/guides/theming).
|
|
531
|
+
|
|
532
|
+
Light + dark mode auto-switch via `prefers-color-scheme`, plus an explicit opt-in via `data-theme="dark"` or `.dark` on any ancestor (or `mode: 'dark'` on `NDPRThemeProvider`).
|
|
394
533
|
|
|
395
534
|
**Per-instance override via slot map:**
|
|
396
535
|
```tsx
|
|
@@ -425,6 +564,7 @@ Each component exports its `ClassNames` TypeScript interface for autocomplete. F
|
|
|
425
564
|
| `/server` | **Pure validators, generators, scoring, locales, adapters, types — zero React** | `tslib` | **Yes** |
|
|
426
565
|
| `/core` | Types, utility functions, NDPRProvider | `react`[^core] | Partial |
|
|
427
566
|
| `/hooks` | React hooks for all 8 modules | `react` | No |
|
|
567
|
+
| `/headless` | **Alias of `/hooks`** — identical exports under a more discoverable name (3.10.0) | `react` | No |
|
|
428
568
|
| `/presets` | All zero-config preset components (barrel) | `react`, Radix peers | No |
|
|
429
569
|
| `/presets/consent` | **Just `NDPRConsent`** — narrower barrel for bundle size | `react`, Radix peers | No |
|
|
430
570
|
| `/presets/dsr` | **Just `NDPRSubjectRights`** | `react`, Radix peers | No |
|
|
@@ -436,8 +576,11 @@ Each component exports its `ClassNames` TypeScript interface for autocomplete. F
|
|
|
436
576
|
| `/breach` | Breach components + hook | `react` | No |
|
|
437
577
|
| `/policy` | Policy components + hook | `react`, `jspdf`, `docx` (optional) | No |
|
|
438
578
|
| `/lawful-basis` | Lawful basis component + hook | `react` | No |
|
|
579
|
+
| `/lawful-basis/lite` | Read-only `LawfulBasisTrackerLite` — ~65% smaller than `/lawful-basis` | `react` | No |
|
|
439
580
|
| `/cross-border` | Cross-border component + hook | `react` | No |
|
|
581
|
+
| `/cross-border/lite` | Read-only `CrossBorderTransferManagerLite` — ~89% smaller (skips the 624-row adequacy dataset) | `react` | No |
|
|
440
582
|
| `/ropa` | ROPA component + hook | `react` | No |
|
|
583
|
+
| `/ropa/lite` | Read-only `ROPAManagerLite` — ~64% smaller than `/ropa` | `react` | No |
|
|
441
584
|
| `/unstyled` | All published components with `unstyled` defaulted to `true` | `react` | No |
|
|
442
585
|
| `/styles` | Default CSS stylesheet — `import "@tantainnovative/ndpr-toolkit/styles"` once in your app entry | none | N/A |
|
|
443
586
|
|
|
@@ -458,6 +601,8 @@ The toolkit is published with `sideEffects: ["*.css"]`, so a modern bundler (Vit
|
|
|
458
601
|
|
|
459
602
|
If your app only needs the hook (e.g. you're rendering ROPA records inside your own admin UI), import from `/hooks` instead of the feature subpath — the hook chunk doesn't drag the manager component into your bundle.
|
|
460
603
|
|
|
604
|
+
If your page only needs to *display* records (no Add / Edit / Archive / CSV export), reach for the new **Lite** variants from `/lawful-basis/lite`, `/cross-border/lite`, and `/ropa/lite` instead — they save ~65%, 89%, and 64% respectively. See [Lite vs Full managers](https://ndprtoolkit.com.ng/docs/guides/lite-vs-full).
|
|
605
|
+
|
|
461
606
|
4. **`/server` carries zero React.** For Server Actions, Route Handlers, scheduled jobs, or compliance-score computation in CI, prefer `/server` and you'll pay no React-tree cost.
|
|
462
607
|
|
|
463
608
|
---
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import {a}from'./chunk-XJO4DH3L.mjs';import {d,a as a$1}from'./chunk-ZJYULEER.mjs';import {jsx}from'react/jsx-runtime';var
|
|
1
|
+
import {a}from'./chunk-XJO4DH3L.mjs';import {d,a as a$1}from'./chunk-ZJYULEER.mjs';import {jsx}from'react/jsx-runtime';var q=[{id:"access",name:"Access My Data",description:"Request a copy of your personal data held by us",ndpaSection:"Section 34(1)(a)\u2013(b)",estimatedCompletionTime:30,requiresAdditionalInfo:false},{id:"rectification",name:"Correct My Data",description:"Request corrections to inaccurate personal data",ndpaSection:"Section 34(1)(c)",estimatedCompletionTime:30,requiresAdditionalInfo:true,additionalFields:[{id:"correction_details",label:"What data needs to be corrected?",type:"textarea",required:true,placeholder:"Please describe the inaccurate data and what the correct information should be"}]},{id:"erasure",name:"Delete My Data",description:"Request deletion of your personal data",ndpaSection:"Section 34(1)(d), Section 34(2)",estimatedCompletionTime:30,requiresAdditionalInfo:false},{id:"portability",name:"Export My Data",description:"Receive your data in a portable format",ndpaSection:"Section 38",estimatedCompletionTime:30,requiresAdditionalInfo:false},{id:"restrict",name:"Restrict Processing",description:"Request restriction of data processing",ndpaSection:"Section 34(1)(e)",estimatedCompletionTime:30,requiresAdditionalInfo:false},{id:"object",name:"Object to Processing",description:"Object to processing of your personal data",ndpaSection:"Section 36",estimatedCompletionTime:30,requiresAdditionalInfo:false},{id:"withdraw_consent",name:"Withdraw My Consent",description:"Withdraw consent previously given for processing",ndpaSection:"Section 35",estimatedCompletionTime:30,requiresAdditionalInfo:false}],C=({requestTypes:R=q,adapter:s,classNames:y,unstyled:S,onSubmit:u=()=>{},submitTo:n,submitOptions:e,onSubmitError:t,onSubmitSuccess:r})=>jsx(a,{requestTypes:R,onSubmit:a=>d(null,null,function*(){var d,c;if(n){let h=typeof(e==null?void 0:e.headers)=="function"?e.headers():(d=e==null?void 0:e.headers)!=null?d:{};try{let o=yield fetch(n,{method:"POST",headers:a$1({"Content-Type":"application/json"},h),credentials:(c=e==null?void 0:e.credentials)!=null?c:"same-origin",body:JSON.stringify(a)});if(!o.ok)t==null||t({response:o});else if(r){let l;try{let i=yield o.clone().text();i&&(l=JSON.parse(i));}catch(i){}r({response:o,data:a,body:l});}}catch(o){t==null||t({error:o});}}else s&&s.save(a);u(a);}),classNames:y,unstyled:S});export{C as a};
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use strict';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
'use strict';var chunkW47OSMT6_js=require('./chunk-W47OSMT6.js'),chunkRFPLZDIO_js=require('./chunk-RFPLZDIO.js'),jsxRuntime=require('react/jsx-runtime');var
|
|
1
|
+
'use strict';var chunkW47OSMT6_js=require('./chunk-W47OSMT6.js'),chunkRFPLZDIO_js=require('./chunk-RFPLZDIO.js'),jsxRuntime=require('react/jsx-runtime');var q=[{id:"access",name:"Access My Data",description:"Request a copy of your personal data held by us",ndpaSection:"Section 34(1)(a)\u2013(b)",estimatedCompletionTime:30,requiresAdditionalInfo:false},{id:"rectification",name:"Correct My Data",description:"Request corrections to inaccurate personal data",ndpaSection:"Section 34(1)(c)",estimatedCompletionTime:30,requiresAdditionalInfo:true,additionalFields:[{id:"correction_details",label:"What data needs to be corrected?",type:"textarea",required:true,placeholder:"Please describe the inaccurate data and what the correct information should be"}]},{id:"erasure",name:"Delete My Data",description:"Request deletion of your personal data",ndpaSection:"Section 34(1)(d), Section 34(2)",estimatedCompletionTime:30,requiresAdditionalInfo:false},{id:"portability",name:"Export My Data",description:"Receive your data in a portable format",ndpaSection:"Section 38",estimatedCompletionTime:30,requiresAdditionalInfo:false},{id:"restrict",name:"Restrict Processing",description:"Request restriction of data processing",ndpaSection:"Section 34(1)(e)",estimatedCompletionTime:30,requiresAdditionalInfo:false},{id:"object",name:"Object to Processing",description:"Object to processing of your personal data",ndpaSection:"Section 36",estimatedCompletionTime:30,requiresAdditionalInfo:false},{id:"withdraw_consent",name:"Withdraw My Consent",description:"Withdraw consent previously given for processing",ndpaSection:"Section 35",estimatedCompletionTime:30,requiresAdditionalInfo:false}],C=({requestTypes:R=q,adapter:s,classNames:y,unstyled:S,onSubmit:u=()=>{},submitTo:n,submitOptions:e,onSubmitError:t,onSubmitSuccess:r})=>jsxRuntime.jsx(chunkW47OSMT6_js.a,{requestTypes:R,onSubmit:a=>chunkRFPLZDIO_js.d(null,null,function*(){var d,c;if(n){let h=typeof(e==null?void 0:e.headers)=="function"?e.headers():(d=e==null?void 0:e.headers)!=null?d:{};try{let o=yield fetch(n,{method:"POST",headers:chunkRFPLZDIO_js.a({"Content-Type":"application/json"},h),credentials:(c=e==null?void 0:e.credentials)!=null?c:"same-origin",body:JSON.stringify(a)});if(!o.ok)t==null||t({response:o});else if(r){let l;try{let i=yield o.clone().text();i&&(l=JSON.parse(i));}catch(i){}r({response:o,data:a,body:l});}}catch(o){t==null||t({error:o});}}else s&&s.save(a);u(a);}),classNames:y,unstyled:S});exports.a=C;
|
package/dist/core.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
'use strict';var chunkUAV7V4EM_js=require('./chunk-UAV7V4EM.js'),chunk4QXTB3L6_js=require('./chunk-4QXTB3L6.js'),chunk3GRGYT3P_js=require('./chunk-3GRGYT3P.js'),chunk7IFSWCQP_js=require('./chunk-7IFSWCQP.js'),
|
|
1
|
+
'use strict';var chunkUAV7V4EM_js=require('./chunk-UAV7V4EM.js'),chunk4QXTB3L6_js=require('./chunk-4QXTB3L6.js'),chunk3GRGYT3P_js=require('./chunk-3GRGYT3P.js'),chunk7IFSWCQP_js=require('./chunk-7IFSWCQP.js'),chunkQPRYXVH2_js=require('./chunk-QPRYXVH2.js'),chunk3YTAOT5O_js=require('./chunk-3YTAOT5O.js'),chunkLVGT3DLT_js=require('./chunk-LVGT3DLT.js'),chunkQ64735OC_js=require('./chunk-Q64735OC.js'),chunkYFBDJ4FH_js=require('./chunk-YFBDJ4FH.js'),chunkWZYCBW2R_js=require('./chunk-WZYCBW2R.js'),chunk4CVBQC66_js=require('./chunk-4CVBQC66.js'),chunk3IA3KDII_js=require('./chunk-3IA3KDII.js'),chunkB46SJB5V_js=require('./chunk-B46SJB5V.js'),chunkUXUMYP4L_js=require('./chunk-UXUMYP4L.js'),chunkL2BRFMVS_js=require('./chunk-L2BRFMVS.js'),chunkTQZWJGJ2_js=require('./chunk-TQZWJGJ2.js'),chunkZVOIR4QH_js=require('./chunk-ZVOIR4QH.js');require('./chunk-RFPLZDIO.js');Object.defineProperty(exports,"NDPRProvider",{enumerable:true,get:function(){return chunkUAV7V4EM_js.a}});Object.defineProperty(exports,"useNDPRConfig",{enumerable:true,get:function(){return chunkUAV7V4EM_js.b}});Object.defineProperty(exports,"useNDPRLocale",{enumerable:true,get:function(){return chunkUAV7V4EM_js.c}});Object.defineProperty(exports,"hausaLocale",{enumerable:true,get:function(){return chunk4QXTB3L6_js.c}});Object.defineProperty(exports,"igboLocale",{enumerable:true,get:function(){return chunk4QXTB3L6_js.b}});Object.defineProperty(exports,"pidginLocale",{enumerable:true,get:function(){return chunk4QXTB3L6_js.d}});Object.defineProperty(exports,"yorubaLocale",{enumerable:true,get:function(){return chunk4QXTB3L6_js.a}});Object.defineProperty(exports,"ORG_POLICY_TEMPLATE_REGISTRY",{enumerable:true,get:function(){return chunk3GRGYT3P_js.a}});Object.defineProperty(exports,"createOrgTemplate",{enumerable:true,get:function(){return chunk3GRGYT3P_js.b}});Object.defineProperty(exports,"templateContextFor",{enumerable:true,get:function(){return chunk3GRGYT3P_js.b}});Object.defineProperty(exports,"defaultLocale",{enumerable:true,get:function(){return chunk7IFSWCQP_js.a}});Object.defineProperty(exports,"mergeLocale",{enumerable:true,get:function(){return chunk7IFSWCQP_js.b}});Object.defineProperty(exports,"getComplianceScore",{enumerable:true,get:function(){return chunkQPRYXVH2_js.a}});Object.defineProperty(exports,"calculateBreachSeverity",{enumerable:true,get:function(){return chunk3YTAOT5O_js.a}});Object.defineProperty(exports,"DEFAULT_POLICY_SECTIONS",{enumerable:true,get:function(){return chunkLVGT3DLT_js.c}});Object.defineProperty(exports,"DEFAULT_POLICY_VARIABLES",{enumerable:true,get:function(){return chunkLVGT3DLT_js.d}});Object.defineProperty(exports,"createBusinessPolicyTemplate",{enumerable:true,get:function(){return chunkLVGT3DLT_js.e}});Object.defineProperty(exports,"findUnfilledTokens",{enumerable:true,get:function(){return chunkLVGT3DLT_js.a}});Object.defineProperty(exports,"generatePolicyText",{enumerable:true,get:function(){return chunkLVGT3DLT_js.b}});Object.defineProperty(exports,"assemblePolicy",{enumerable:true,get:function(){return chunkQ64735OC_js.c}});Object.defineProperty(exports,"createDefaultContext",{enumerable:true,get:function(){return chunkQ64735OC_js.e}});Object.defineProperty(exports,"evaluatePolicyCompliance",{enumerable:true,get:function(){return chunkQ64735OC_js.f}});Object.defineProperty(exports,"assessTransferRisk",{enumerable:true,get:function(){return chunkYFBDJ4FH_js.h}});Object.defineProperty(exports,"getTransferMechanismDescription",{enumerable:true,get:function(){return chunkYFBDJ4FH_js.f}});Object.defineProperty(exports,"isNDPCApprovalRequired",{enumerable:true,get:function(){return chunkYFBDJ4FH_js.e}});Object.defineProperty(exports,"validateTransfer",{enumerable:true,get:function(){return chunkYFBDJ4FH_js.g}});Object.defineProperty(exports,"assessComplianceGaps",{enumerable:true,get:function(){return chunkWZYCBW2R_js.c}});Object.defineProperty(exports,"generateLawfulBasisSummary",{enumerable:true,get:function(){return chunkWZYCBW2R_js.d}});Object.defineProperty(exports,"getLawfulBasisDescription",{enumerable:true,get:function(){return chunkWZYCBW2R_js.b}});Object.defineProperty(exports,"validateProcessingActivity",{enumerable:true,get:function(){return chunkWZYCBW2R_js.a}});Object.defineProperty(exports,"exportROPAToCSV",{enumerable:true,get:function(){return chunk4CVBQC66_js.c}});Object.defineProperty(exports,"generateROPASummary",{enumerable:true,get:function(){return chunk4CVBQC66_js.b}});Object.defineProperty(exports,"identifyComplianceGaps",{enumerable:true,get:function(){return chunk4CVBQC66_js.d}});Object.defineProperty(exports,"validateProcessingRecord",{enumerable:true,get:function(){return chunk4CVBQC66_js.a}});Object.defineProperty(exports,"appendAuditEntry",{enumerable:true,get:function(){return chunk3IA3KDII_js.c}});Object.defineProperty(exports,"createAuditEntry",{enumerable:true,get:function(){return chunk3IA3KDII_js.a}});Object.defineProperty(exports,"getAuditLog",{enumerable:true,get:function(){return chunk3IA3KDII_js.b}});Object.defineProperty(exports,"validateConsent",{enumerable:true,get:function(){return chunkB46SJB5V_js.a}});Object.defineProperty(exports,"validateConsentOptions",{enumerable:true,get:function(){return chunkB46SJB5V_js.b}});Object.defineProperty(exports,"sanitizeInput",{enumerable:true,get:function(){return chunkUXUMYP4L_js.a}});Object.defineProperty(exports,"formatDSRRequest",{enumerable:true,get:function(){return chunkL2BRFMVS_js.b}});Object.defineProperty(exports,"validateDsrSubmission",{enumerable:true,get:function(){return chunkL2BRFMVS_js.a}});Object.defineProperty(exports,"assessDPIARisk",{enumerable:true,get:function(){return chunkTQZWJGJ2_js.a}});Object.defineProperty(exports,"LEGAL_DISCLAIMER_LONG",{enumerable:true,get:function(){return chunkZVOIR4QH_js.b}});Object.defineProperty(exports,"LEGAL_DISCLAIMER_SHORT",{enumerable:true,get:function(){return chunkZVOIR4QH_js.a}});Object.defineProperty(exports,"legalDisclaimerBlock",{enumerable:true,get:function(){return chunkZVOIR4QH_js.c}});
|
package/dist/core.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{a as NDPRProvider,b as useNDPRConfig,c as useNDPRLocale}from'./chunk-EEQALYOY.mjs';export{c as hausaLocale,b as igboLocale,d as pidginLocale,a as yorubaLocale}from'./chunk-LQTARVPU.mjs';export{a as ORG_POLICY_TEMPLATE_REGISTRY,b as createOrgTemplate,b as templateContextFor}from'./chunk-UKLU6BQF.mjs';export{a as defaultLocale,b as mergeLocale}from'./chunk-HWHBINVN.mjs';export{c as DEFAULT_POLICY_SECTIONS,d as DEFAULT_POLICY_VARIABLES,e as createBusinessPolicyTemplate,a as findUnfilledTokens,b as generatePolicyText}from'./chunk-Y3MKMAFQ.mjs';export{
|
|
1
|
+
export{a as NDPRProvider,b as useNDPRConfig,c as useNDPRLocale}from'./chunk-EEQALYOY.mjs';export{c as hausaLocale,b as igboLocale,d as pidginLocale,a as yorubaLocale}from'./chunk-LQTARVPU.mjs';export{a as ORG_POLICY_TEMPLATE_REGISTRY,b as createOrgTemplate,b as templateContextFor}from'./chunk-UKLU6BQF.mjs';export{a as defaultLocale,b as mergeLocale}from'./chunk-HWHBINVN.mjs';export{a as getComplianceScore}from'./chunk-EFIBHKQE.mjs';export{a as calculateBreachSeverity}from'./chunk-WTGKZX7J.mjs';export{c as DEFAULT_POLICY_SECTIONS,d as DEFAULT_POLICY_VARIABLES,e as createBusinessPolicyTemplate,a as findUnfilledTokens,b as generatePolicyText}from'./chunk-Y3MKMAFQ.mjs';export{c as assemblePolicy,e as createDefaultContext,f as evaluatePolicyCompliance}from'./chunk-RMQ7OLNY.mjs';export{h as assessTransferRisk,f as getTransferMechanismDescription,e as isNDPCApprovalRequired,g as validateTransfer}from'./chunk-7BJXI2HI.mjs';export{c as assessComplianceGaps,d as generateLawfulBasisSummary,b as getLawfulBasisDescription,a as validateProcessingActivity}from'./chunk-LWIKDDSU.mjs';export{c as exportROPAToCSV,b as generateROPASummary,d as identifyComplianceGaps,a as validateProcessingRecord}from'./chunk-XP5PL6K7.mjs';export{c as appendAuditEntry,a as createAuditEntry,b as getAuditLog}from'./chunk-V7UFP6QU.mjs';export{a as validateConsent,b as validateConsentOptions}from'./chunk-PJNKQPQP.mjs';export{a as sanitizeInput}from'./chunk-EWVK45Z3.mjs';export{b as formatDSRRequest,a as validateDsrSubmission}from'./chunk-RZ6GC6WN.mjs';export{a as assessDPIARisk}from'./chunk-LRRENTT5.mjs';export{b as LEGAL_DISCLAIMER_LONG,a as LEGAL_DISCLAIMER_SHORT,c as legalDisclaimerBlock}from'./chunk-ITCY2Z66.mjs';import'./chunk-ZJYULEER.mjs';
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import React__default from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Adequacy status of a destination country
|
|
5
|
+
*/
|
|
6
|
+
export declare type AdequacyStatus = 'adequate' | 'inadequate' | 'pending_review' | 'unknown';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Summary of cross-border transfer compliance
|
|
10
|
+
*/
|
|
11
|
+
export declare interface CrossBorderSummary {
|
|
12
|
+
/** Total number of active transfers */
|
|
13
|
+
totalActiveTransfers: number;
|
|
14
|
+
/** Breakdown by transfer mechanism */
|
|
15
|
+
byMechanism: Record<TransferMechanism, number>;
|
|
16
|
+
/** Breakdown by adequacy status */
|
|
17
|
+
byAdequacy: Record<AdequacyStatus, number>;
|
|
18
|
+
/** Transfers pending NDPC approval */
|
|
19
|
+
pendingApproval: CrossBorderTransfer[];
|
|
20
|
+
/** Transfers due for review */
|
|
21
|
+
dueForReview: CrossBorderTransfer[];
|
|
22
|
+
/** Transfers missing TIA */
|
|
23
|
+
missingTIA: CrossBorderTransfer[];
|
|
24
|
+
/** High-risk transfers */
|
|
25
|
+
highRiskTransfers: CrossBorderTransfer[];
|
|
26
|
+
/** Last updated timestamp */
|
|
27
|
+
lastUpdated: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Represents a cross-border data transfer record
|
|
32
|
+
*/
|
|
33
|
+
export declare interface CrossBorderTransfer {
|
|
34
|
+
/** Unique identifier */
|
|
35
|
+
id: string;
|
|
36
|
+
/** Destination country or territory */
|
|
37
|
+
destinationCountry: string;
|
|
38
|
+
/** ISO country code */
|
|
39
|
+
destinationCountryCode?: string;
|
|
40
|
+
/** Adequacy status of the destination */
|
|
41
|
+
adequacyStatus: AdequacyStatus;
|
|
42
|
+
/** The transfer mechanism being relied upon */
|
|
43
|
+
transferMechanism: TransferMechanism;
|
|
44
|
+
/** Categories of personal data being transferred */
|
|
45
|
+
dataCategories: string[];
|
|
46
|
+
/** Whether sensitive personal data is included */
|
|
47
|
+
includesSensitiveData: boolean;
|
|
48
|
+
/** Estimated number of data subjects whose data is transferred */
|
|
49
|
+
estimatedDataSubjects?: number;
|
|
50
|
+
/** Name of the recipient organization */
|
|
51
|
+
recipientOrganization: string;
|
|
52
|
+
/** Contact details of the recipient */
|
|
53
|
+
recipientContact: {
|
|
54
|
+
name: string;
|
|
55
|
+
email: string;
|
|
56
|
+
phone?: string;
|
|
57
|
+
address?: string;
|
|
58
|
+
};
|
|
59
|
+
/** Purpose of the data transfer */
|
|
60
|
+
purpose: string;
|
|
61
|
+
/** Safeguards in place to protect the data */
|
|
62
|
+
safeguards: string[];
|
|
63
|
+
/** Risk assessment summary */
|
|
64
|
+
riskAssessment: string;
|
|
65
|
+
/** Risk level of the transfer */
|
|
66
|
+
riskLevel: 'low' | 'medium' | 'high';
|
|
67
|
+
/** NDPC approval details (required for some transfer mechanisms) */
|
|
68
|
+
ndpcApproval?: {
|
|
69
|
+
required: boolean;
|
|
70
|
+
applied: boolean;
|
|
71
|
+
approved?: boolean;
|
|
72
|
+
referenceNumber?: string;
|
|
73
|
+
appliedAt?: number;
|
|
74
|
+
approvedAt?: number;
|
|
75
|
+
};
|
|
76
|
+
/** Whether a Transfer Impact Assessment has been conducted */
|
|
77
|
+
tiaCompleted: boolean;
|
|
78
|
+
/** Reference to the TIA document */
|
|
79
|
+
tiaReference?: string;
|
|
80
|
+
/** Frequency of the transfer */
|
|
81
|
+
frequency: 'one_time' | 'periodic' | 'continuous';
|
|
82
|
+
/** Start date of the transfer */
|
|
83
|
+
startDate: number;
|
|
84
|
+
/** End date of the transfer (if applicable) */
|
|
85
|
+
endDate?: number;
|
|
86
|
+
/** Status of the transfer */
|
|
87
|
+
status: 'active' | 'suspended' | 'terminated' | 'pending_approval';
|
|
88
|
+
/** Timestamp when the record was created */
|
|
89
|
+
createdAt: number;
|
|
90
|
+
/** Timestamp when the record was last updated */
|
|
91
|
+
updatedAt: number;
|
|
92
|
+
/** Next review date */
|
|
93
|
+
reviewDate?: number;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Read-only, lightweight variant of {@link CrossBorderTransferManager}. Renders the
|
|
98
|
+
* list + summary view without pulling in the full adequacy dataset, and exposes
|
|
99
|
+
* no add/edit/delete affordances.
|
|
100
|
+
*/
|
|
101
|
+
export declare const CrossBorderTransferManagerLite: React__default.FC<CrossBorderTransferManagerLiteProps>;
|
|
102
|
+
|
|
103
|
+
export declare interface CrossBorderTransferManagerLiteClassNames {
|
|
104
|
+
root?: string;
|
|
105
|
+
header?: string;
|
|
106
|
+
title?: string;
|
|
107
|
+
summary?: string;
|
|
108
|
+
summaryCard?: string;
|
|
109
|
+
table?: string;
|
|
110
|
+
tableHeader?: string;
|
|
111
|
+
tableRow?: string;
|
|
112
|
+
statusBadge?: string;
|
|
113
|
+
riskBadge?: string;
|
|
114
|
+
riskAlert?: string;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export declare interface CrossBorderTransferManagerLiteProps {
|
|
118
|
+
transfers: CrossBorderTransfer[];
|
|
119
|
+
title?: string;
|
|
120
|
+
description?: string;
|
|
121
|
+
className?: string;
|
|
122
|
+
classNames?: CrossBorderTransferManagerLiteClassNames;
|
|
123
|
+
unstyled?: boolean;
|
|
124
|
+
showSummary?: boolean;
|
|
125
|
+
showRiskAlerts?: boolean;
|
|
126
|
+
onTransferClick?: (transfer: CrossBorderTransfer) => void;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Cross-Border Data Transfer types aligned with NDPA 2023 Part VIII (Sections 41-43).
|
|
131
|
+
* Personal data may only be transferred outside Nigeria under the bases listed in
|
|
132
|
+
* Section 41(1), where Section 42 defines adequacy and Section 43 lists derogations.
|
|
133
|
+
*
|
|
134
|
+
* Note: These are guidance labels — not legal advice. Verify with your DPO or counsel.
|
|
135
|
+
*/
|
|
136
|
+
/**
|
|
137
|
+
* Transfer mechanisms recognized under the NDPA
|
|
138
|
+
*/
|
|
139
|
+
export declare type TransferMechanism = 'adequacy_decision' | 'standard_clauses' | 'binding_corporate_rules' | 'ndpc_authorization' | 'explicit_consent' | 'contract_performance' | 'public_interest' | 'legal_claims' | 'vital_interests';
|
|
140
|
+
|
|
141
|
+
export { }
|