@consenti/api 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +387 -90
- package/dist/chunk-IY4L6MNB.js +2 -0
- package/dist/chunk-IY4L6MNB.js.map +1 -0
- package/dist/chunk-O5UG4OYI.js +2 -0
- package/dist/chunk-O5UG4OYI.js.map +1 -0
- package/dist/dashboard/assets/ApiConfig-CE-Noelz.js +1 -0
- package/dist/dashboard/assets/ArchivedProfileList-Bw-fx-BD.js +1 -0
- package/dist/dashboard/assets/AuditLog-D6HiTQ1o.js +1 -0
- package/dist/dashboard/assets/ChangePassword-D2rPkzD1.js +1 -0
- package/dist/dashboard/assets/ConfirmDialog-DTtw7VJ-.js +1 -0
- package/dist/dashboard/assets/ConsentList-BWOvPOMG.js +1 -0
- package/dist/dashboard/assets/ConsentTemplateEditor-BKIEnLmA.js +1 -0
- package/dist/dashboard/assets/ConsentTemplateList-DCys2nM3.js +1 -0
- package/dist/dashboard/assets/HeadingTagInput-BTjrdzlS.js +1 -0
- package/dist/dashboard/assets/HowItWorks-AeyjfQGO.js +1 -0
- package/dist/dashboard/assets/PermissionGate-Bhhf7SMh.js +1 -0
- package/dist/dashboard/assets/PreviewPane-Dq5K1h2L.js +35 -0
- package/dist/dashboard/assets/ProfileEditor-BXtaE0tL.js +2 -0
- package/dist/dashboard/assets/ProfileList-CWKSAgu0.js +1 -0
- package/dist/dashboard/assets/ProfileVersionHistory-1h8sUgog.js +3 -0
- package/dist/dashboard/assets/RecordDetailModal-FaFhzQXi.js +1 -0
- package/dist/dashboard/assets/Reports-DWEjQOKh.js +1 -0
- package/dist/dashboard/assets/RoleList-BSGoqlzp.js +1 -0
- package/dist/dashboard/assets/Select-DjJNwlbY.js +1 -0
- package/dist/dashboard/assets/Settings-CVYrlyLm.js +1 -0
- package/dist/dashboard/assets/SetupWizard-4NTb5bZj.js +1 -0
- package/dist/dashboard/assets/Table-DH_jh8_N.js +1 -0
- package/dist/dashboard/assets/TenantList-5AwFtoHf.js +1 -0
- package/dist/dashboard/assets/UITemplateEditor-9A55scBe.js +1 -0
- package/dist/dashboard/assets/UITemplateList-BS7X4u4F.js +1 -0
- package/dist/dashboard/assets/UserList-SPkMyFRy.js +1 -0
- package/dist/dashboard/assets/VendorList-C5fPhr6U.js +1 -0
- package/dist/dashboard/assets/VisitorList-COP1SyNd.js +1 -0
- package/dist/dashboard/assets/check-o5cp1s2J.js +1 -0
- package/dist/dashboard/assets/client-ymc9nwWr.js +1 -0
- package/dist/dashboard/assets/copy-C01KoUUH.js +1 -0
- package/dist/dashboard/assets/createLucideIcon-MdjI3m3u.js +1 -0
- package/dist/dashboard/assets/de-DET92Jb5.js +5 -0
- package/dist/dashboard/assets/debounce-DlvAAT2V.js +1 -0
- package/dist/dashboard/assets/dist-DlhLroYC.js +1 -0
- package/dist/dashboard/assets/es-CJNunrnU.js +5 -0
- package/dist/dashboard/assets/external-link-DVe00ZBK.js +1 -0
- package/dist/dashboard/assets/fr-akfTuf5x.js +5 -0
- package/dist/dashboard/assets/history-CHTts_m2.js +1 -0
- package/dist/dashboard/assets/index-DW3qOrry.css +2 -0
- package/dist/dashboard/assets/index-H_Zm0X-u.js +6 -0
- package/dist/dashboard/assets/ja-B0nLWkOd.js +5 -0
- package/dist/dashboard/assets/profiles-DmrdGv7t.js +1 -0
- package/dist/dashboard/assets/roles-C0dJPFl4.js +1 -0
- package/dist/dashboard/assets/search-Bd2RdDRh.js +1 -0
- package/dist/dashboard/assets/templates-B2xiivh4.js +1 -0
- package/dist/dashboard/assets/templates-CnMoLavN.js +1 -0
- package/dist/dashboard/assets/trash-2-BBnkdgm_.js +1 -0
- package/dist/dashboard/assets/trash-Dj1jhzHJ.js +1 -0
- package/dist/dashboard/assets/useHashQuery-B5ytMIMp.js +1 -0
- package/dist/dashboard/assets/users-czK8LRVh.js +1 -0
- package/dist/dashboard/assets/x-BRuyBEQP.js +1 -0
- package/dist/dashboard/assets/zh-CN-Dxg3G-BL.js +5 -0
- package/dist/dashboard/index.html +4 -2
- package/dist/dist-Z5RVTVBT.js +2 -0
- package/dist/dist-Z5RVTVBT.js.map +1 -0
- package/dist/index.cjs +89 -100
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +663 -128
- package/dist/index.d.ts +663 -128
- package/dist/index.js +90 -101
- package/dist/index.js.map +1 -1
- package/dist/profiles-XTYPWLVC.js +2 -0
- package/dist/profiles-XTYPWLVC.js.map +1 -0
- package/dist/widget/widget.css +1 -1
- package/dist/widget/widget.js +1 -1
- package/package.json +14 -14
- package/dist/dashboard/assets/de-DwE2aQfW.js +0 -5
- package/dist/dashboard/assets/es-Dq88TWkB.js +0 -5
- package/dist/dashboard/assets/fr-o_Pyg8eR.js +0 -5
- package/dist/dashboard/assets/index-BSsYDdb9.js +0 -40
- package/dist/dashboard/assets/index-bOTGevzl.css +0 -2
- package/dist/dashboard/assets/ja-CwgXYmpD.js +0 -5
- package/dist/dashboard/assets/zh-CN-ety9KoQ0.js +0 -5
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
2
|
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Deep-partial with JSON Merge Patch (RFC 7396) delete semantics: any key may be
|
|
6
|
+
* set to `null` instead of its usual type to signal "delete this key" when the
|
|
7
|
+
* partial is applied with `deepMerge()` — `undefined`/omitted keeps the base
|
|
8
|
+
* value, `null` removes it. Only meaningful for object/map keys (e.g. removing
|
|
9
|
+
* a `CategoryMap`/`CookieMap` entry via `profileOverride`); array elements are
|
|
10
|
+
* merged positionally and don't support deletion this way.
|
|
11
|
+
*/
|
|
12
|
+
type DeepPartial<T> = T extends Function ? T : T extends Array<infer InferredArrayType> ? Array<DeepPartial<InferredArrayType>> : T extends ReadonlyArray<infer InferredReadonlyArrayType> ? ReadonlyArray<DeepPartial<InferredReadonlyArrayType>> : T extends object ? {
|
|
13
|
+
[Key in keyof T]?: DeepPartial<T[Key]> | null;
|
|
14
|
+
} : T;
|
|
15
|
+
|
|
4
16
|
declare const COMPLIANCE_GROUP_IDS: readonly ["opt-in", "opt-out", "opt-out-strict", "opt-in-dpdpa", "opt-in-china", "opt-in-brazil", "general-privacy-consent", "notice-only"];
|
|
17
|
+
declare const COOKIE_PURPOSE_IDS: readonly ["necessary", "functional", "preferences", "analytics", "marketing"];
|
|
5
18
|
|
|
6
19
|
/**
|
|
7
20
|
* Compliance-related literal types, derived from the regulation/group ID data
|
|
@@ -18,6 +31,18 @@ declare const COMPLIANCE_GROUP_IDS: readonly ["opt-in", "opt-out", "opt-out-stri
|
|
|
18
31
|
|
|
19
32
|
type ComplianceGroupId = typeof COMPLIANCE_GROUP_IDS[number];
|
|
20
33
|
|
|
34
|
+
/** Resolved content for one non-default locale — template shape merged with that locale's
|
|
35
|
+
* author text, computed client-side (dashboard) the same way the default locale's content on
|
|
36
|
+
* `StoredProfileJson` is. Never persisted in the DB row; `ProfileService` writes it straight to
|
|
37
|
+
* that locale's on-disk version file. Keyed by locale code on `CreateProfileInput`/
|
|
38
|
+
* `UpdateProfileInput.localeContent` — only locales actually touched this save need an entry;
|
|
39
|
+
* any other locale already in `profileJson.locales` is carried forward unchanged from the
|
|
40
|
+
* previous version. */
|
|
41
|
+
interface LocaleContentInput {
|
|
42
|
+
mainBanner: MainBanner;
|
|
43
|
+
gpcBanner?: GpcBanner;
|
|
44
|
+
preferenceModal: PreferenceModal;
|
|
45
|
+
}
|
|
21
46
|
interface StorageConfig {
|
|
22
47
|
driver: 'sqlite' | 'better-sqlite3' | 'node-sqlite3-wasm' | 'node:sqlite' | 'mongodb' | 'mysql' | 'postgresql' | 'json';
|
|
23
48
|
path?: string;
|
|
@@ -27,6 +52,20 @@ interface StorageConfig {
|
|
|
27
52
|
port?: number;
|
|
28
53
|
user?: string;
|
|
29
54
|
password?: string;
|
|
55
|
+
/** Postgres/MySQL only. Max pool connections. Default: 10 (both drivers' own default — set
|
|
56
|
+
* explicitly here so it's a documented, tunable value rather than an implicit library default). */
|
|
57
|
+
poolMax?: number;
|
|
58
|
+
/**
|
|
59
|
+
* Postgres/MySQL only. Milliseconds before an in-flight query is aborted, so one slow/runaway
|
|
60
|
+
* query can't hold a pool connection indefinitely. Unset by default: a forced default could
|
|
61
|
+
* silently break legitimate long-running operations (e.g. exporting millions of records) that
|
|
62
|
+
* this project has no way to load-test — opt in once you've measured your own worst-case query.
|
|
63
|
+
*/
|
|
64
|
+
statementTimeoutMs?: number;
|
|
65
|
+
/** Postgres only. Milliseconds a client may sit idle inside an open transaction before being
|
|
66
|
+
* terminated — protects against a `BEGIN` with no matching `COMMIT`/`ROLLBACK` holding a
|
|
67
|
+
* connection forever. Unset by default, same reasoning as `statementTimeoutMs`. */
|
|
68
|
+
idleInTransactionTimeoutMs?: number;
|
|
30
69
|
}
|
|
31
70
|
interface OidcConfig {
|
|
32
71
|
issuer: string;
|
|
@@ -81,18 +120,33 @@ interface ProfileSummary {
|
|
|
81
120
|
name: string;
|
|
82
121
|
defaultLocale: string;
|
|
83
122
|
complianceGroup: ComplianceGroupId | null;
|
|
84
|
-
|
|
123
|
+
customComplianceGroup: string | null;
|
|
85
124
|
isActive: boolean;
|
|
86
|
-
|
|
125
|
+
consentTemplateName: string | null;
|
|
87
126
|
uiTemplateName: string | null;
|
|
88
127
|
createdAt: string;
|
|
89
128
|
updatedAt: string;
|
|
90
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* One snapshot in a profile's edit history. `Profile.id` is stable across edits; each save
|
|
132
|
+
* increments `Profile.version` in place and writes a new snapshot under that version number.
|
|
133
|
+
*/
|
|
91
134
|
interface ProfileVersionEntry {
|
|
92
135
|
version: number;
|
|
93
136
|
createdAt: string;
|
|
94
137
|
locales: string[];
|
|
95
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* A profile-id directory found on disk with no matching DB row — the profile was deleted
|
|
141
|
+
* (or predates the current versioning model) but its version-snapshot history wasn't. Built
|
|
142
|
+
* from a directory listing only (id, version count, last-modified) — no file content is read
|
|
143
|
+
* until a specific version is opened via the normal version-history endpoints.
|
|
144
|
+
*/
|
|
145
|
+
interface ArchivedProfileSummary {
|
|
146
|
+
id: string;
|
|
147
|
+
versionCount: number;
|
|
148
|
+
lastModified: string;
|
|
149
|
+
}
|
|
96
150
|
interface OptInFilters {
|
|
97
151
|
profileId?: string;
|
|
98
152
|
complianceGroup?: string;
|
|
@@ -169,6 +223,11 @@ interface TcfConfig {
|
|
|
169
223
|
}
|
|
170
224
|
interface DataRetentionConfig {
|
|
171
225
|
purgeAfterDays: number;
|
|
226
|
+
/** When set, audit log entries older than this are purged on the same daily timer as consent
|
|
227
|
+
* record retention. Independent of `purgeAfterDays` since audit trails are often required to
|
|
228
|
+
* be kept longer than the consent records they reference for compliance/investigation
|
|
229
|
+
* purposes. Unset by default — audit logs are kept indefinitely unless explicitly configured. */
|
|
230
|
+
auditLogPurgeAfterDays?: number;
|
|
172
231
|
}
|
|
173
232
|
interface BrandingConfig {
|
|
174
233
|
/** Display name shown in the dashboard (login page, header, browser tab). Default: 'Consenti'. */
|
|
@@ -198,8 +257,13 @@ interface ConsentiServerConfig {
|
|
|
198
257
|
trustedProxies?: string[];
|
|
199
258
|
branding?: BrandingConfig;
|
|
200
259
|
s3Api?: S3ApiConfig;
|
|
260
|
+
/** When set, every consent record is HMAC-SHA256 signed at create/update time (hex-encoded,
|
|
261
|
+
* stored in `signature`) and the signature is checked on `GET /consent/:visitorId/verify`.
|
|
262
|
+
* No-op and no schema burden when unset — opt-in tamper-evidence for server-stored records,
|
|
263
|
+
* independent of the widget's own cookie-signing (`core.cookieSigningKey`). */
|
|
264
|
+
consentSigningKey?: string;
|
|
201
265
|
/** Called after every profile activate/deactivate/delete. isPurge=true means invalidate; false means warm. */
|
|
202
|
-
handleCache?: (paths: string[],
|
|
266
|
+
handleCache?: (paths: string[], profileId: string, isPurge: boolean) => void;
|
|
203
267
|
}
|
|
204
268
|
interface Tenant {
|
|
205
269
|
id: string;
|
|
@@ -208,21 +272,42 @@ interface Tenant {
|
|
|
208
272
|
createdAt: string;
|
|
209
273
|
updatedAt: string;
|
|
210
274
|
}
|
|
275
|
+
/** Tenant-wide dashboard-managed defaults, shown on the API Config page. */
|
|
276
|
+
interface TenantSettings {
|
|
277
|
+
/** Public API origin allowlist. Distinct from `ProfileConfig.allowedOrigins`, which the
|
|
278
|
+
* origin check on `POST /consent` prefers when a profile sets its own list; this is the
|
|
279
|
+
* fallback. The public API has no auth token, so this is its only access gate. */
|
|
280
|
+
allowedOrigins?: string[];
|
|
281
|
+
/** Admin API origin allowlist — an additional CORS-layer check on top of Bearer-token auth
|
|
282
|
+
* for browser-originated `/consenti/admin/*` requests. Empty/unset means no restriction
|
|
283
|
+
* (Bearer token auth alone still applies); only enforced when the request carries an
|
|
284
|
+
* `Origin` header — server-to-server callers are unaffected. */
|
|
285
|
+
adminAllowedOrigins?: string[];
|
|
286
|
+
/** Whether this tenant has completed (or skipped) the first-run setup wizard. Gates the
|
|
287
|
+
* one-time `#/setup` redirect in the dashboard — never reset once true. Default: false. */
|
|
288
|
+
setupCompleted?: boolean;
|
|
289
|
+
}
|
|
211
290
|
interface ApiKey {
|
|
212
291
|
id: string;
|
|
213
292
|
tenantId: string;
|
|
214
293
|
keyHash: string;
|
|
215
294
|
name: string;
|
|
216
295
|
isActive: boolean;
|
|
296
|
+
/** User id of the admin who created this key. Undefined for keys created before this field existed. */
|
|
297
|
+
createdBy?: string;
|
|
298
|
+
/** Optional expiry set at creation. Checked lazily at auth time and on list — no background sweep. */
|
|
299
|
+
expireBy?: string;
|
|
217
300
|
createdAt: string;
|
|
301
|
+
updatedAt?: string;
|
|
218
302
|
}
|
|
219
303
|
interface Profile {
|
|
220
304
|
id: string;
|
|
221
305
|
tenantId: string;
|
|
222
306
|
name: string;
|
|
223
307
|
defaultLocale: string;
|
|
308
|
+
/** Starts at 1, incremented in place on every save. The row itself is mutated, never replaced — see {@link ProfileVersionEntry} for the on-disk snapshot history this produces. */
|
|
224
309
|
version: number;
|
|
225
|
-
profileJson:
|
|
310
|
+
profileJson: StoredProfileJson;
|
|
226
311
|
createdAt: string;
|
|
227
312
|
updatedAt: string;
|
|
228
313
|
}
|
|
@@ -231,7 +316,6 @@ interface ConsentDbRecord {
|
|
|
231
316
|
tenantId: string;
|
|
232
317
|
visitorId: string;
|
|
233
318
|
profileId: string;
|
|
234
|
-
profileVersion: number;
|
|
235
319
|
locale: string;
|
|
236
320
|
consentJson: ConsentValue;
|
|
237
321
|
gpcDetected: boolean;
|
|
@@ -239,6 +323,10 @@ interface ConsentDbRecord {
|
|
|
239
323
|
ageVerified?: boolean;
|
|
240
324
|
parentalConsentToken?: string;
|
|
241
325
|
tcfString?: string;
|
|
326
|
+
/** HMAC-SHA256 signature over the record's core fields, hex-encoded. Only present when
|
|
327
|
+
* `consentSigningKey` is configured — opt-in tamper-evidence for server-stored records,
|
|
328
|
+
* independent of the widget's own cookie-signing (`core.cookieSigningKey`). */
|
|
329
|
+
signature?: string;
|
|
242
330
|
createdAt: string;
|
|
243
331
|
updatedAt: string;
|
|
244
332
|
}
|
|
@@ -289,6 +377,22 @@ interface Permission {
|
|
|
289
377
|
name: string;
|
|
290
378
|
description?: string;
|
|
291
379
|
}
|
|
380
|
+
/** Proof that the consent banner was rendered to a visitor — recorded even if they never
|
|
381
|
+
* interact with it, distinct from (and never merged into) an actual consent decision. */
|
|
382
|
+
interface NoticeShownRecord {
|
|
383
|
+
id: string;
|
|
384
|
+
tenantId: string;
|
|
385
|
+
visitorId: string;
|
|
386
|
+
profileId: string;
|
|
387
|
+
locale: string;
|
|
388
|
+
createdAt: string;
|
|
389
|
+
}
|
|
390
|
+
interface CreateNoticeShownInput {
|
|
391
|
+
tenantId: string;
|
|
392
|
+
visitorId: string;
|
|
393
|
+
profileId: string;
|
|
394
|
+
locale: string;
|
|
395
|
+
}
|
|
292
396
|
interface AuditLog {
|
|
293
397
|
id: string;
|
|
294
398
|
tenantId: string;
|
|
@@ -300,22 +404,38 @@ interface AuditLog {
|
|
|
300
404
|
newData?: unknown;
|
|
301
405
|
createdAt: string;
|
|
302
406
|
}
|
|
407
|
+
/** List-view shape for consents — omits the fields not shown in a table row (`consentJson`,
|
|
408
|
+
* `parentalConsentToken`, `tcfString`, `signature`), so paginated list queries don't have to pull
|
|
409
|
+
* those blobs off disk for every row. Fetch the full `ConsentDbRecord` via `getConsent(visitorId)`
|
|
410
|
+
* when a single record's full detail is actually needed (e.g. opening a detail modal). */
|
|
411
|
+
type ConsentSummary = Omit<ConsentDbRecord, 'consentJson' | 'parentalConsentToken' | 'tcfString' | 'signature'>;
|
|
412
|
+
/** List-view shape for audit logs — omits `oldData`/`newData` (full before/after snapshots) for
|
|
413
|
+
* the same reason as `ConsentSummary`. Fetch the full `AuditLog` via `getAuditLogById(id)` when a
|
|
414
|
+
* single entry's full detail is needed. */
|
|
415
|
+
type AuditLogSummary = Omit<AuditLog, 'oldData' | 'newData'>;
|
|
303
416
|
interface CreateProfileInput {
|
|
304
417
|
tenantId: string;
|
|
305
418
|
name: string;
|
|
306
419
|
defaultLocale: string;
|
|
307
|
-
profileJson:
|
|
420
|
+
profileJson: StoredProfileJson;
|
|
421
|
+
/** Non-default locales' resolved content for this save — see {@link LocaleContentInput}. */
|
|
422
|
+
localeContent?: Record<string, LocaleContentInput>;
|
|
308
423
|
}
|
|
309
424
|
interface UpdateProfileInput {
|
|
310
425
|
name?: string;
|
|
311
426
|
defaultLocale?: string;
|
|
312
|
-
profileJson?:
|
|
427
|
+
profileJson?: StoredProfileJson;
|
|
428
|
+
/** Explicit new version number — set by `ProfileService.update()` to `old.version + 1` for a content edit. Omitted for isActive-only flips (activate/deactivate), which leave the version unchanged. */
|
|
429
|
+
version?: number;
|
|
430
|
+
/** Non-default locales' resolved content for this save — see {@link LocaleContentInput}. Any
|
|
431
|
+
* locale in `profileJson.locales` not present here is carried forward unchanged from the
|
|
432
|
+
* previous version's on-disk file. */
|
|
433
|
+
localeContent?: Record<string, LocaleContentInput>;
|
|
313
434
|
}
|
|
314
435
|
interface CreateConsentInput {
|
|
315
436
|
tenantId: string;
|
|
316
437
|
visitorId: string;
|
|
317
438
|
profileId: string;
|
|
318
|
-
profileVersion: number;
|
|
319
439
|
locale: string;
|
|
320
440
|
consentJson: ConsentValue;
|
|
321
441
|
gpcDetected: boolean;
|
|
@@ -323,11 +443,13 @@ interface CreateConsentInput {
|
|
|
323
443
|
ageVerified?: boolean;
|
|
324
444
|
parentalConsentToken?: string;
|
|
325
445
|
tcfString?: string;
|
|
446
|
+
signature?: string;
|
|
326
447
|
}
|
|
327
448
|
interface UpdateConsentInput {
|
|
328
449
|
consentJson: ConsentValue;
|
|
329
450
|
locale?: string;
|
|
330
451
|
gpcDetected?: boolean;
|
|
452
|
+
signature?: string;
|
|
331
453
|
}
|
|
332
454
|
interface CreateVisitorInput {
|
|
333
455
|
tenantId: string;
|
|
@@ -376,6 +498,8 @@ interface ConsentFilters {
|
|
|
376
498
|
to?: string;
|
|
377
499
|
page?: number;
|
|
378
500
|
limit?: number;
|
|
501
|
+
/** Free-text search across visitorId, profileId, locale, source. */
|
|
502
|
+
q?: string;
|
|
379
503
|
}
|
|
380
504
|
interface VisitorFilters {
|
|
381
505
|
tenantId: string;
|
|
@@ -383,6 +507,8 @@ interface VisitorFilters {
|
|
|
383
507
|
to?: string;
|
|
384
508
|
page?: number;
|
|
385
509
|
limit?: number;
|
|
510
|
+
/** Free-text search across visitorId, country. */
|
|
511
|
+
q?: string;
|
|
386
512
|
}
|
|
387
513
|
interface AuditFilters {
|
|
388
514
|
tenantId: string;
|
|
@@ -392,12 +518,24 @@ interface AuditFilters {
|
|
|
392
518
|
to?: string;
|
|
393
519
|
page?: number;
|
|
394
520
|
limit?: number;
|
|
521
|
+
/** Free-text search across action, resourceType, resourceId, userId. */
|
|
522
|
+
q?: string;
|
|
523
|
+
}
|
|
524
|
+
/** Page of results plus the total row count matching the same filters (ignoring page/limit) —
|
|
525
|
+
* lets callers compute total page count for numbered pagination without a second round trip. */
|
|
526
|
+
interface PagedResult<T> {
|
|
527
|
+
items: T[];
|
|
528
|
+
total: number;
|
|
529
|
+
page: number;
|
|
530
|
+
limit: number;
|
|
395
531
|
}
|
|
396
532
|
interface ConsentVerifyResult {
|
|
397
533
|
valid: boolean;
|
|
398
|
-
reasons: Array<'
|
|
399
|
-
|
|
400
|
-
|
|
534
|
+
reasons: Array<'profile_changed' | 'consent_expired' | 'hmac_invalid'>;
|
|
535
|
+
/** The id of the profile currently active for this consent's compliance group, if any. */
|
|
536
|
+
currentProfileId?: string;
|
|
537
|
+
/** The id of the profile this consent was originally collected against. */
|
|
538
|
+
consentProfileId?: string;
|
|
401
539
|
}
|
|
402
540
|
type SafeAdminUser = Omit<AdminUser, 'passwordHash'>;
|
|
403
541
|
interface CreateRoleInput {
|
|
@@ -438,6 +576,8 @@ interface CreateApiKeyInput {
|
|
|
438
576
|
tenantId: string;
|
|
439
577
|
name: string;
|
|
440
578
|
keyHash: string;
|
|
579
|
+
createdBy?: string;
|
|
580
|
+
expireBy?: string;
|
|
441
581
|
}
|
|
442
582
|
interface CreateTenantInput {
|
|
443
583
|
name: string;
|
|
@@ -459,22 +599,24 @@ interface StorageAdapter {
|
|
|
459
599
|
findActiveProfileByComplianceGroup(tenantId: string, complianceGroup: string): Promise<Profile | null>;
|
|
460
600
|
/** Lightweight list — no profile_json blob; single JOIN for template names. */
|
|
461
601
|
listProfilesSummary(tenantId: string): Promise<ProfileSummary[]>;
|
|
462
|
-
|
|
602
|
+
findProfilesUsingConsentTemplate(templateId: string): Promise<ProfileSummary[]>;
|
|
463
603
|
findProfilesUsingUITemplate(templateId: string): Promise<ProfileSummary[]>;
|
|
464
604
|
getOptInStats(tenantId: string, filters: OptInFilters): Promise<OptInStats>;
|
|
465
605
|
createConsent(data: CreateConsentInput): Promise<ConsentDbRecord>;
|
|
466
606
|
updateConsent(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord>;
|
|
467
607
|
deleteConsent(visitorId: string): Promise<void>;
|
|
468
608
|
getConsent(visitorId: string): Promise<ConsentDbRecord | null>;
|
|
469
|
-
getConsents(filters: ConsentFilters): Promise<
|
|
609
|
+
getConsents(filters: ConsentFilters): Promise<PagedResult<ConsentSummary>>;
|
|
470
610
|
streamConsents(filters: ConsentFilters): AsyncIterable<ConsentDbRecord>;
|
|
471
611
|
createVisitor(data: CreateVisitorInput): Promise<Visitor>;
|
|
472
612
|
updateVisitor(visitorId: string, data: UpdateVisitorInput): Promise<Visitor>;
|
|
473
613
|
deleteVisitor(visitorId: string): Promise<void>;
|
|
474
614
|
getVisitor(visitorId: string): Promise<Visitor | null>;
|
|
475
|
-
getVisitors(filters: VisitorFilters): Promise<Visitor
|
|
615
|
+
getVisitors(filters: VisitorFilters): Promise<PagedResult<Visitor>>;
|
|
476
616
|
getConsentHistory(visitorId: string): Promise<ConsentHistoryEntry[]>;
|
|
477
617
|
streamAuditLogs(filters: AuditFilters): AsyncIterable<AuditLog>;
|
|
618
|
+
createNoticeShown(data: CreateNoticeShownInput): Promise<NoticeShownRecord>;
|
|
619
|
+
getNoticeShownForVisitor(visitorId: string): Promise<NoticeShownRecord[]>;
|
|
478
620
|
getOverviewStats(tenantId: string): Promise<OverviewStats>;
|
|
479
621
|
getCategoryStats(tenantId: string): Promise<CategoryStats>;
|
|
480
622
|
getTimeline(tenantId: string, days?: number): Promise<TimelineEntry[]>;
|
|
@@ -484,17 +626,26 @@ interface StorageAdapter {
|
|
|
484
626
|
createTenant(data: CreateTenantInput): Promise<Tenant>;
|
|
485
627
|
updateTenant(id: string, data: UpdateTenantInput): Promise<Tenant>;
|
|
486
628
|
deleteTenant(id: string): Promise<void>;
|
|
629
|
+
/** Returns `{}` (all fields unset) if no settings row exists yet for this tenant. */
|
|
630
|
+
getSettings(tenantId: string): Promise<TenantSettings>;
|
|
631
|
+
updateSettings(tenantId: string, data: Partial<TenantSettings>): Promise<TenantSettings>;
|
|
487
632
|
createApiKey(data: CreateApiKeyInput): Promise<ApiKey>;
|
|
488
633
|
getApiKeyByHash(keyHash: string): Promise<ApiKey | null>;
|
|
489
634
|
revokeApiKey(id: string): Promise<void>;
|
|
635
|
+
/** Re-enables a previously revoked key (same hash, no new secret). Clears `expireBy` if it's
|
|
636
|
+
* in the past, so a lazily-expired key doesn't immediately re-expire on the next check. */
|
|
637
|
+
reactivateApiKey(id: string): Promise<void>;
|
|
638
|
+
/** Permanently removes the key row — unlike `revokeApiKey`, this cannot be undone. */
|
|
639
|
+
deleteApiKey(id: string): Promise<void>;
|
|
490
640
|
getApiKeys(tenantId: string): Promise<ApiKey[]>;
|
|
491
641
|
purgeExpiredConsents(olderThanDays: number): Promise<number>;
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
642
|
+
purgeExpiredAuditLogs(olderThanDays: number): Promise<number>;
|
|
643
|
+
createConsentTemplate(data: CreateConsentTemplateInput): Promise<ServerConsentTemplate>;
|
|
644
|
+
updateConsentTemplate(id: string, data: UpdateConsentTemplateInput): Promise<ServerConsentTemplate>;
|
|
645
|
+
deleteConsentTemplate(id: string): Promise<void>;
|
|
646
|
+
getConsentTemplate(id: string): Promise<ServerConsentTemplate | null>;
|
|
647
|
+
getConsentTemplates(tenantId: string): Promise<ServerConsentTemplate[]>;
|
|
648
|
+
copyConsentTemplate(id: string, newName: string): Promise<ServerConsentTemplate>;
|
|
498
649
|
createUITemplate(data: CreateUITemplateInput): Promise<ServerUITemplate>;
|
|
499
650
|
updateUITemplate(id: string, data: UpdateUITemplateInput): Promise<ServerUITemplate>;
|
|
500
651
|
deleteUITemplate(id: string): Promise<void>;
|
|
@@ -520,7 +671,8 @@ interface StorageAdapter {
|
|
|
520
671
|
assignPermissionToRole(roleId: string, permissionId: string): Promise<void>;
|
|
521
672
|
revokePermissionFromRole(roleId: string, permissionId: string): Promise<void>;
|
|
522
673
|
createLog(data: CreateAuditLogInput): Promise<void>;
|
|
523
|
-
getLogs(filters: AuditFilters): Promise<
|
|
674
|
+
getLogs(filters: AuditFilters): Promise<PagedResult<AuditLogSummary>>;
|
|
675
|
+
getAuditLogById(id: string): Promise<AuditLog | null>;
|
|
524
676
|
}
|
|
525
677
|
interface PluginContext {
|
|
526
678
|
storage: StorageAdapter;
|
|
@@ -539,23 +691,54 @@ declare abstract class ConsentiServerPlugin {
|
|
|
539
691
|
beforeUserCreate?(data: CreateUserInput): Promise<CreateUserInput>;
|
|
540
692
|
afterUserCreate?(user: AdminUser): Promise<void>;
|
|
541
693
|
}
|
|
694
|
+
/**
|
|
695
|
+
* The server's stored shape of `Profile.profileJson` — extends the shared `ProfileConfig`
|
|
696
|
+
* (`./ui`, also used by `apps/ui`'s local `ConsentiProfile`/`registerProfile()` authoring, which
|
|
697
|
+
* genuinely needs the full multi-locale `translations`/`localeContents` blob for its own
|
|
698
|
+
* no-backend use case and must stay untouched).
|
|
699
|
+
*
|
|
700
|
+
* On the server, only `defaultLocale`'s own resolved content is ever stored here —
|
|
701
|
+
* `mainBanner`/`gpcBanner`/`preferenceModal` (inherited from `ProfileConfig` as-is: template shape
|
|
702
|
+
* merged with the author's text, optional fields simply omitted rather than blank — never a
|
|
703
|
+
* multi-locale map). Every other locale's content lives only in its own per-version JSON file on
|
|
704
|
+
* disk (`profiles/{tenant}/{id}/{version}/{locale}.json`, see `ProfileService`), never in the DB
|
|
705
|
+
* row — `translations`/`localeContents` (both full multi-locale blobs) are dropped entirely.
|
|
706
|
+
*/
|
|
707
|
+
interface StoredProfileJson extends Omit<ProfileConfig, 'translations' | 'localeContents'> {
|
|
708
|
+
/** Every locale this profile has content for — drives the dashboard's tab list. Content for any
|
|
709
|
+
* locale other than `defaultLocale` lives only in that locale's on-disk version file, not here. */
|
|
710
|
+
locales: string[];
|
|
711
|
+
}
|
|
542
712
|
|
|
543
713
|
type ConsentStatus = 'granted' | 'denied' | 'objected';
|
|
544
714
|
type ConsentValue = Record<string, ConsentStatus>;
|
|
715
|
+
type GpcMode = 'ignore' | 'honor' | 'strict';
|
|
716
|
+
type LegalBasis = 'mandatory' | 'consent' | 'legitimate_interest';
|
|
717
|
+
type CookiePurpose = typeof COOKIE_PURPOSE_IDS[number];
|
|
718
|
+
/**
|
|
719
|
+
* A single consent parameter (tracker/cookie definition).
|
|
720
|
+
* Keyed by its own id inside `Record<string, Cookie>` — the map key IS the id,
|
|
721
|
+
* there is no `id` field on the value itself.
|
|
722
|
+
*/
|
|
545
723
|
interface Cookie {
|
|
546
|
-
|
|
547
|
-
legalBasis?: 'mandatory' | 'consent' | 'legitimate_interest';
|
|
548
|
-
/** @deprecated use legalBasis: 'mandatory' */
|
|
549
|
-
mandatory?: boolean;
|
|
550
|
-
/** @deprecated use legalBasis */
|
|
551
|
-
type?: 'consent' | 'legitimate_interest';
|
|
724
|
+
purpose?: CookiePurpose;
|
|
552
725
|
listenGpc?: boolean;
|
|
553
|
-
|
|
726
|
+
/**
|
|
727
|
+
* Pre-grant this parameter's default consent to 'granted' (instead of the
|
|
728
|
+
* compliance-group-driven default) when no stored decision exists yet.
|
|
729
|
+
* Only meaningful when the owning category's `legalBasis === 'consent'` —
|
|
730
|
+
* `mandatory`/`legitimate_interest` categories are already effectively
|
|
731
|
+
* pre-granted regardless of this flag. Never overrides an active GPC signal.
|
|
732
|
+
* Default: false.
|
|
733
|
+
*/
|
|
734
|
+
preGrant?: boolean;
|
|
554
735
|
tcfVendorId?: number;
|
|
555
736
|
tcfPurposes?: number[];
|
|
556
737
|
tcfSpecialFeatures?: number[];
|
|
557
738
|
cpraCategory?: 'sale' | 'sharing' | 'sensitive';
|
|
558
739
|
}
|
|
740
|
+
/** `Cookie` keyed by its own id — the standard shape used everywhere a parameter list is passed around. */
|
|
741
|
+
type CookieMap = Record<string, Cookie>;
|
|
559
742
|
type ButtonStyle = 'primary' | 'secondary' | 'text' | 'accent';
|
|
560
743
|
type ButtonAction = 'submit' | 'manage' | 'close' | 'custom' | 'link';
|
|
561
744
|
interface Button {
|
|
@@ -564,8 +747,11 @@ interface Button {
|
|
|
564
747
|
action: ButtonAction;
|
|
565
748
|
cookies?: string[] | '*' | '!';
|
|
566
749
|
url?: string;
|
|
567
|
-
type?: string;
|
|
568
750
|
}
|
|
751
|
+
/** `Button` keyed by its own id — e.g. `'accept-all'`. The map key IS the id, rendered as the DOM
|
|
752
|
+
* `id` (`consenti-btn-{id}`) so integrators can target specific buttons, and is what
|
|
753
|
+
* `profileOverride`'s `deepMerge` deletes by (`{ 'reject-optional': null }` removes one button). */
|
|
754
|
+
type ButtonMap = Record<string, Button>;
|
|
569
755
|
interface MainBanner {
|
|
570
756
|
position: 'top' | 'bottom' | 'middle' | 'left-bottom' | 'right-bottom';
|
|
571
757
|
overlayOpacity?: number;
|
|
@@ -574,34 +760,84 @@ interface MainBanner {
|
|
|
574
760
|
heading?: string;
|
|
575
761
|
headingTag?: string;
|
|
576
762
|
htmlText: string;
|
|
577
|
-
buttons:
|
|
763
|
+
buttons: ButtonMap;
|
|
764
|
+
/** Stack buttons vertically below this viewport width in px. 0 or undefined = disabled. Default: 576. */
|
|
765
|
+
stackButtonsOnBreakpoint?: number;
|
|
766
|
+
/** Trap keyboard Tab focus within the consent root while this banner is visible. */
|
|
767
|
+
trapFocus?: boolean;
|
|
578
768
|
}
|
|
579
769
|
type GpcBanner = MainBanner;
|
|
770
|
+
/**
|
|
771
|
+
* A consent category — the single source of legal basis for every parameter
|
|
772
|
+
* it lists in `cookies`. Keyed by its own id inside `Record<string, Category>` —
|
|
773
|
+
* the map key IS the id, there is no `id` field on the value itself.
|
|
774
|
+
*
|
|
775
|
+
* A parameter must belong to exactly one category (enforced at authoring time,
|
|
776
|
+
* not by this type) — that relationship is what `getCookieLegalBasis`/
|
|
777
|
+
* `isMandatoryCookie` (`@consenti/utils`) resolve at runtime.
|
|
778
|
+
*/
|
|
580
779
|
interface Category {
|
|
581
|
-
id: string;
|
|
582
780
|
heading: string;
|
|
583
781
|
headingTag?: string;
|
|
584
782
|
htmlText: string;
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
description?: string;
|
|
590
|
-
};
|
|
783
|
+
legalBasis: LegalBasis;
|
|
784
|
+
/** Only meaningful when legalBasis === 'legitimate_interest' — the GDPR balancing-test justification shown to visitors. */
|
|
785
|
+
legitimateInterestDescription?: string;
|
|
786
|
+
/** IDs of the parameters (from the profile's `cookies` map) that belong to this category. */
|
|
591
787
|
cookies: string[];
|
|
592
788
|
}
|
|
789
|
+
/** `Category` keyed by its own id — the standard shape used everywhere a category list is passed around. */
|
|
790
|
+
type CategoryMap = Record<string, Category>;
|
|
593
791
|
interface PreferenceModal extends Omit<MainBanner, "position"> {
|
|
594
792
|
position?: 'left' | 'right' | 'center';
|
|
595
793
|
subheading?: string;
|
|
596
|
-
categories:
|
|
794
|
+
categories: CategoryMap;
|
|
597
795
|
persistent?: boolean;
|
|
598
796
|
/** Screen width in px below which the modal expands to full screen. Default: 576. Set to 0 to disable. */
|
|
599
797
|
mobileFullScreenBreakpoint?: number;
|
|
798
|
+
/** Label for the optional consent-receipt download checkbox (shown when `allowReceipt` is true). Falls back to a default when omitted. */
|
|
799
|
+
receiptLabel?: string;
|
|
800
|
+
/** Description shown beneath the consent-receipt checkbox. Falls back to a default when omitted. */
|
|
801
|
+
receiptDescription?: string;
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* A UI-template button definition. Keyed by its own machine id (e.g. `'accept-all'`) inside
|
|
805
|
+
* `TemplateButtonMap` — the map key IS the id, not display text. UI templates own layout/behavior
|
|
806
|
+
* only, never text. The visitor-facing label is authored per-locale on the profile instead
|
|
807
|
+
* (`LocaleTextContent.*.buttonLabels`, keyed by the same button id) and composed into a resolved
|
|
808
|
+
* `Button.text` at profile-build time. Distinct from `Button` (the resolved-profile shape), which
|
|
809
|
+
* always carries real `text`.
|
|
810
|
+
*/
|
|
811
|
+
interface TemplateButtonDef {
|
|
812
|
+
type?: ButtonStyle;
|
|
813
|
+
action: ButtonAction;
|
|
814
|
+
cookies?: string[] | '*' | '!';
|
|
815
|
+
url?: string;
|
|
816
|
+
}
|
|
817
|
+
/** `TemplateButtonDef` keyed by its own id — the standard shape everywhere a UI template's
|
|
818
|
+
* button set is passed around. */
|
|
819
|
+
type TemplateButtonMap = Record<string, TemplateButtonDef>;
|
|
820
|
+
interface TemplateBannerDef {
|
|
821
|
+
position: 'top' | 'bottom' | 'middle' | 'left-bottom' | 'right-bottom';
|
|
822
|
+
overlayOpacity?: number;
|
|
823
|
+
showClose?: boolean;
|
|
824
|
+
showLocaleSwitcher?: boolean;
|
|
825
|
+
headingTag?: string;
|
|
826
|
+
buttons: TemplateButtonMap;
|
|
827
|
+
stackButtonsOnBreakpoint?: number;
|
|
828
|
+
trapFocus?: boolean;
|
|
829
|
+
}
|
|
830
|
+
type TemplateGpcBannerDef = TemplateBannerDef;
|
|
831
|
+
interface TemplateModalDef extends Omit<TemplateBannerDef, 'position'> {
|
|
832
|
+
position?: 'left' | 'right' | 'center';
|
|
833
|
+
persistent?: boolean;
|
|
834
|
+
hasSubheading?: boolean;
|
|
835
|
+
mobileFullScreenBreakpoint?: number;
|
|
600
836
|
}
|
|
601
837
|
interface LocaleTranslations {
|
|
602
|
-
mainBanner: MainBanner
|
|
603
|
-
gpcBanner?: GpcBanner
|
|
604
|
-
preferenceModal: PreferenceModal
|
|
838
|
+
mainBanner: DeepPartial<MainBanner>;
|
|
839
|
+
gpcBanner?: DeepPartial<GpcBanner>;
|
|
840
|
+
preferenceModal: DeepPartial<PreferenceModal>;
|
|
605
841
|
}
|
|
606
842
|
interface ProfileTranslations {
|
|
607
843
|
[locale: string]: LocaleTranslations;
|
|
@@ -615,109 +851,162 @@ interface LocaleTextContent {
|
|
|
615
851
|
mainBanner: {
|
|
616
852
|
heading?: string;
|
|
617
853
|
htmlText: string;
|
|
618
|
-
|
|
854
|
+
/** Keyed by the linked UI template's button id — was a positional array matched to
|
|
855
|
+
* `buttons[i]` by index; now matched by key, robust against button reordering. */
|
|
856
|
+
buttonLabels?: Record<string, string>;
|
|
619
857
|
};
|
|
620
858
|
gpcBanner: {
|
|
621
859
|
heading?: string;
|
|
622
860
|
htmlText: string;
|
|
623
|
-
buttonLabels?: string
|
|
861
|
+
buttonLabels?: Record<string, string>;
|
|
624
862
|
};
|
|
625
863
|
preferenceModal: {
|
|
626
864
|
heading: string;
|
|
627
865
|
subheading?: string;
|
|
628
866
|
htmlText?: string;
|
|
629
|
-
buttonLabels?: string
|
|
630
|
-
categories
|
|
631
|
-
|
|
867
|
+
buttonLabels?: Record<string, string>;
|
|
868
|
+
/** `legitimateInterestDescription` is only meaningful for categories whose legalBasis is 'legitimate_interest'; optional GDPR balancing-test text, translated per locale like heading/htmlText. */
|
|
869
|
+
categories: Record<string, {
|
|
632
870
|
heading: string;
|
|
633
871
|
htmlText: string;
|
|
634
|
-
|
|
872
|
+
legitimateInterestDescription?: string;
|
|
873
|
+
}>;
|
|
874
|
+
receiptLabel?: string;
|
|
875
|
+
receiptDescription?: string;
|
|
635
876
|
};
|
|
636
877
|
}
|
|
637
878
|
interface ProfileConfig {
|
|
638
|
-
|
|
879
|
+
id: string;
|
|
880
|
+
cookies?: CookieMap;
|
|
639
881
|
defaultLocale: string;
|
|
882
|
+
/** Days until consent expires and the visitor is asked again (profile-wide). Default: 365. */
|
|
883
|
+
expiryDays?: number;
|
|
640
884
|
translations?: ProfileTranslations;
|
|
641
|
-
|
|
885
|
+
mainBanner: MainBanner;
|
|
886
|
+
gpcBanner?: GpcBanner;
|
|
887
|
+
preferenceModal: PreferenceModal;
|
|
642
888
|
darkMode?: boolean;
|
|
643
889
|
allowedOrigins?: string[];
|
|
644
890
|
dpdpa?: DpdpaConfig;
|
|
645
891
|
regulation?: 'gdpr' | 'ccpa' | 'cpra' | 'dpdpa' | 'uk-gdpr' | 'lgpd' | 'pipeda' | 'popia' | 'pdpa-th' | 'appi' | 'kvkk';
|
|
646
892
|
regulations?: string[];
|
|
647
|
-
|
|
893
|
+
consentTemplateId?: string;
|
|
648
894
|
uiTemplateId?: string;
|
|
649
895
|
localeContents?: Record<string, LocaleTextContent>;
|
|
650
|
-
complianceGroup?:
|
|
651
|
-
/**
|
|
652
|
-
|
|
653
|
-
|
|
896
|
+
complianceGroup?: ComplianceGroupId;
|
|
897
|
+
/**
|
|
898
|
+
* Free-form identifier (lower-kebab-case) for profiles that don't map to one of the
|
|
899
|
+
* built-in `complianceGroup` values — the identifier the widget's `compliance.type`
|
|
900
|
+
* config targets to fetch this profile. Participates in activation, deactivation, and
|
|
901
|
+
* "one active profile per group" conflict detection the same way `complianceGroup` does;
|
|
902
|
+
* no `COMPLIANCE_GROUPS` validation rules or GPC defaults apply to it, since none exist
|
|
903
|
+
* for a free-form name.
|
|
904
|
+
*/
|
|
905
|
+
customComplianceGroup?: string;
|
|
906
|
+
/**
|
|
907
|
+
* Per-profile deltas applied on top of the consent template's authored `Cookie` values
|
|
908
|
+
* (e.g. an overridden `preGrant`) when resolving this profile — see the dashboard's Step 2
|
|
909
|
+
* pre-grant override UX. Keyed by cookie id; only the overridden fields need to be present.
|
|
910
|
+
*/
|
|
911
|
+
cookiesOverride?: Record<string, Partial<Cookie>>;
|
|
912
|
+
/**
|
|
913
|
+
* Reserved for a future phase — stored but not yet applied when resolving a profile.
|
|
914
|
+
* Intended to mirror `cookiesOverride` for per-category deltas.
|
|
915
|
+
*/
|
|
916
|
+
categoriesOverride?: Record<string, Partial<Category>>;
|
|
917
|
+
/**
|
|
918
|
+
* Reserved for a future phase — stored but not yet applied when resolving a profile.
|
|
919
|
+
* Intended to hold per-profile UI-template deltas.
|
|
920
|
+
*/
|
|
921
|
+
uiOverride?: Record<string, unknown>;
|
|
922
|
+
/**
|
|
923
|
+
* When registered via `registerProfile()` and `complianceGroup` matches one of
|
|
924
|
+
* Consenti's built-in groups: `false` (default) fully replaces the built-in
|
|
925
|
+
* embedded profile for that group; `true` deep-merges this config onto the
|
|
926
|
+
* built-in profile instead (only meaningful together with `complianceGroup`).
|
|
927
|
+
*/
|
|
928
|
+
deepMerge?: boolean;
|
|
929
|
+
gpcMode?: GpcMode;
|
|
654
930
|
isActive?: boolean;
|
|
655
931
|
hidePoweredBy?: boolean;
|
|
656
932
|
allowReceipt?: boolean;
|
|
657
933
|
/** Per-compliance extra config (e.g. DPDPA data fiduciary name). */
|
|
658
934
|
complianceConfig?: Record<string, string>;
|
|
935
|
+
/** Show a metadata footer strip in the banner/modal with Consent ID, Date, Version, Privacy Settings link. */
|
|
936
|
+
showFooterMetadata?: boolean;
|
|
937
|
+
/** Apply WCAG 2.1 AA button sizing (44px min-height), visible focus rings, and screen-reader labels. */
|
|
938
|
+
enhanceAccessibility?: boolean;
|
|
659
939
|
}
|
|
660
940
|
interface ServerUITemplate {
|
|
661
941
|
id: string;
|
|
662
942
|
tenantId: string;
|
|
663
943
|
name: string;
|
|
664
|
-
mainBanner:
|
|
665
|
-
gpcBanner:
|
|
666
|
-
preferenceModal:
|
|
944
|
+
mainBanner: TemplateBannerDef;
|
|
945
|
+
gpcBanner: TemplateGpcBannerDef;
|
|
946
|
+
preferenceModal: TemplateModalDef;
|
|
667
947
|
createdAt: string;
|
|
668
948
|
updatedAt: string;
|
|
669
949
|
}
|
|
670
|
-
interface
|
|
950
|
+
interface ServerConsentTemplate {
|
|
671
951
|
id: string;
|
|
672
952
|
tenantId: string;
|
|
673
953
|
name: string;
|
|
674
|
-
cookies:
|
|
954
|
+
cookies: CookieMap;
|
|
955
|
+
categories: CategoryMap;
|
|
675
956
|
createdAt: string;
|
|
676
957
|
updatedAt: string;
|
|
677
958
|
}
|
|
678
|
-
interface
|
|
959
|
+
interface CreateConsentTemplateInput {
|
|
679
960
|
tenantId: string;
|
|
680
961
|
name: string;
|
|
681
|
-
cookies:
|
|
962
|
+
cookies: CookieMap;
|
|
963
|
+
categories: CategoryMap;
|
|
682
964
|
}
|
|
683
|
-
interface
|
|
965
|
+
interface UpdateConsentTemplateInput {
|
|
684
966
|
name?: string;
|
|
685
|
-
cookies?:
|
|
967
|
+
cookies?: CookieMap;
|
|
968
|
+
categories?: CategoryMap;
|
|
686
969
|
}
|
|
687
970
|
interface CreateUITemplateInput {
|
|
688
971
|
tenantId: string;
|
|
689
972
|
name: string;
|
|
690
|
-
mainBanner:
|
|
691
|
-
gpcBanner:
|
|
692
|
-
preferenceModal:
|
|
973
|
+
mainBanner: TemplateBannerDef;
|
|
974
|
+
gpcBanner: TemplateGpcBannerDef;
|
|
975
|
+
preferenceModal: TemplateModalDef;
|
|
693
976
|
}
|
|
694
977
|
interface UpdateUITemplateInput {
|
|
695
978
|
name?: string;
|
|
696
|
-
mainBanner?:
|
|
697
|
-
gpcBanner?:
|
|
698
|
-
preferenceModal?:
|
|
979
|
+
mainBanner?: TemplateBannerDef;
|
|
980
|
+
gpcBanner?: TemplateGpcBannerDef;
|
|
981
|
+
preferenceModal?: TemplateModalDef;
|
|
699
982
|
}
|
|
700
983
|
interface PublicProfileResponse {
|
|
701
984
|
id: string;
|
|
985
|
+
/** Incremented in place on every save of this profile. */
|
|
986
|
+
version: number;
|
|
702
987
|
name?: string;
|
|
703
988
|
tenantId?: string;
|
|
704
|
-
version: number;
|
|
705
989
|
defaultLocale: string;
|
|
706
990
|
currentLocale: string;
|
|
707
991
|
locales: string[];
|
|
708
|
-
cookies:
|
|
992
|
+
cookies: CookieMap;
|
|
993
|
+
/** Days until consent expires and the visitor is asked again (profile-wide). */
|
|
994
|
+
expiryDays?: number;
|
|
709
995
|
mainBanner: MainBanner;
|
|
710
996
|
gpcBanner?: GpcBanner;
|
|
711
997
|
preferenceModal: PreferenceModal;
|
|
712
998
|
resolvedComplianceGroup?: string;
|
|
713
|
-
complianceGroup?:
|
|
999
|
+
complianceGroup?: ComplianceGroupId;
|
|
714
1000
|
compliances?: string[];
|
|
715
1001
|
complianceConfig?: Record<string, string>;
|
|
716
1002
|
allowedOrigins?: string[];
|
|
717
|
-
gpcMode?:
|
|
1003
|
+
gpcMode?: GpcMode;
|
|
718
1004
|
hidePoweredBy?: boolean;
|
|
719
1005
|
allowReceipt?: boolean;
|
|
720
1006
|
darkMode?: boolean;
|
|
1007
|
+
dpdpa?: DpdpaConfig;
|
|
1008
|
+
showFooterMetadata?: boolean;
|
|
1009
|
+
enhanceAccessibility?: boolean;
|
|
721
1010
|
createdAt?: string;
|
|
722
1011
|
updatedAt?: string;
|
|
723
1012
|
}
|
|
@@ -737,7 +1026,8 @@ declare class AuditRepo {
|
|
|
737
1026
|
private adapter;
|
|
738
1027
|
constructor(adapter: StorageAdapter);
|
|
739
1028
|
log(data: CreateAuditLogInput): Promise<void>;
|
|
740
|
-
list(filters: AuditFilters): Promise<
|
|
1029
|
+
list(filters: AuditFilters): Promise<PagedResult<AuditLogSummary>>;
|
|
1030
|
+
get(id: string): Promise<AuditLog | null>;
|
|
741
1031
|
}
|
|
742
1032
|
|
|
743
1033
|
declare class LocaleJsonCacheService {
|
|
@@ -760,23 +1050,96 @@ declare class ProfileService {
|
|
|
760
1050
|
private profilesDir?;
|
|
761
1051
|
private handleCache?;
|
|
762
1052
|
private s3Config?;
|
|
763
|
-
constructor(profiles: ProfileRepo, audit: AuditRepo, tenantId?: string, storage?: StorageAdapter | undefined, eventBus?: EventEmitter | undefined, localeCache?: LocaleJsonCacheService | undefined, profilesDir?: string | undefined, handleCache?: ((paths: string[],
|
|
764
|
-
|
|
1053
|
+
constructor(profiles: ProfileRepo, audit: AuditRepo, tenantId?: string, storage?: StorageAdapter | undefined, eventBus?: EventEmitter | undefined, localeCache?: LocaleJsonCacheService | undefined, profilesDir?: string | undefined, handleCache?: ((paths: string[], profileId: string, isPurge: boolean) => void) | undefined, s3Config?: S3ApiConfig | undefined);
|
|
1054
|
+
/** Root directory holding every version snapshot of one logical profile, keyed by its stable id. */
|
|
1055
|
+
private versionsRootDir;
|
|
765
1056
|
private complianceGroupDir;
|
|
1057
|
+
/**
|
|
1058
|
+
* The directory key used for activation/hot-serve writes and the "one active profile
|
|
1059
|
+
* per group" conflict check — the real `complianceGroup` when set, otherwise the
|
|
1060
|
+
* free-form `customComplianceGroup` (which the widget's `compliance.type` targets the
|
|
1061
|
+
* same way). Compliance *validation* still only ever runs against a real `complianceGroup`.
|
|
1062
|
+
*/
|
|
1063
|
+
private groupKey;
|
|
766
1064
|
private profileFilePaths;
|
|
1065
|
+
/** Resolves this profile's cookie map (consent-template lookup + `cookiesOverride` applied) —
|
|
1066
|
+
* the one piece of content still resolved live rather than baked at save time, since cookies
|
|
1067
|
+
* are small and never the source of the row-size problem `mainBanner`/`preferenceModal` were. */
|
|
1068
|
+
private resolveCookies;
|
|
1069
|
+
/**
|
|
1070
|
+
* Writes every locale's on-disk version file for one save (create or an edit) in a single
|
|
1071
|
+
* atomic worker call — default locale content comes from `profile.profileJson` itself, every
|
|
1072
|
+
* other touched locale from `localeContent`. A locale already in `profileJson.locales` but not
|
|
1073
|
+
* present in `localeContent` (a tab the user never opened this session) is carried forward
|
|
1074
|
+
* unchanged from `previousVersion` by the worker — never silently dropped.
|
|
1075
|
+
*/
|
|
1076
|
+
private writeLocaleFiles;
|
|
767
1077
|
create(input: Omit<CreateProfileInput, 'tenantId'>): Promise<Profile>;
|
|
1078
|
+
/**
|
|
1079
|
+
* Duplicates a profile as a brand new, always-inactive profile (own `id`, `version` starts at
|
|
1080
|
+
* 1 again). Delegates to {@link create} rather than copying on-disk files directly — the
|
|
1081
|
+
* resolved-JSON snapshot embeds its own `id`/`version`, so it has to be regenerated for the
|
|
1082
|
+
* new profile rather than byte-copied from the source's. Non-default locale content is read
|
|
1083
|
+
* back off the source's current version files so the copy carries every locale forward too.
|
|
1084
|
+
*/
|
|
1085
|
+
copy(id: string, name?: string): Promise<Profile>;
|
|
1086
|
+
/**
|
|
1087
|
+
* Mutates the existing row in place — `id` is stable across every edit, `version` is
|
|
1088
|
+
* incremented. The prior state isn't kept as a separate DB row; its resolved-JSON snapshot
|
|
1089
|
+
* on disk (see {@link listVersions}) is the audit trail for that edit.
|
|
1090
|
+
*/
|
|
768
1091
|
update(id: string, input: UpdateProfileInput): Promise<Profile>;
|
|
769
1092
|
delete(id: string): Promise<void>;
|
|
770
1093
|
activate(id: string): Promise<Profile>;
|
|
771
1094
|
deactivate(id: string): Promise<Profile>;
|
|
772
|
-
private
|
|
773
|
-
get(id: string
|
|
1095
|
+
private runDeactivate;
|
|
1096
|
+
get(id: string): Promise<Profile | null>;
|
|
1097
|
+
/**
|
|
1098
|
+
* Resolves one locale's full public response. The default locale's content lives directly on
|
|
1099
|
+
* the DB row (`profileJson.mainBanner`/`gpcBanner`/`preferenceModal`) — no template lookups, no
|
|
1100
|
+
* live resolution. Any other locale's content lives only in that locale's on-disk version file;
|
|
1101
|
+
* this reads it directly, falling back to the default locale's content if the file is missing
|
|
1102
|
+
* (e.g. a locale listed but never actually authored yet). This method is not a hot path — the
|
|
1103
|
+
* public `/profiles/:tenant/:group/:locale` route serves the static file directly and only
|
|
1104
|
+
* falls back to this for previewing an inactive/versioned profile.
|
|
1105
|
+
*/
|
|
774
1106
|
getResolved(id: string, locale?: string): Promise<PublicProfileResponse | null>;
|
|
775
1107
|
findActiveByComplianceGroup(complianceGroup: string): Promise<Profile | null>;
|
|
776
1108
|
list(): Promise<Profile[]>;
|
|
777
1109
|
listSummary(): Promise<ProfileSummary[]>;
|
|
778
|
-
|
|
779
|
-
|
|
1110
|
+
/**
|
|
1111
|
+
* Lists every version snapshot of `profileId` on disk (newest first), read straight from
|
|
1112
|
+
* the version-directory tree — no DB query, `Profile.version` is just the current pointer.
|
|
1113
|
+
* Works for archived profiles too (DB row deleted, files still on disk) — the directory
|
|
1114
|
+
* tree is the only thing this reads.
|
|
1115
|
+
*/
|
|
1116
|
+
listVersions(profileId: string): Promise<ProfileVersionEntry[]>;
|
|
1117
|
+
/** Works for archived profiles too — see `listVersions()`. */
|
|
1118
|
+
getVersionFile(profileId: string, version: string, locale: string): Promise<string | null>;
|
|
1119
|
+
/**
|
|
1120
|
+
* Profile-id directories on disk with no matching DB row — deleted profiles whose version
|
|
1121
|
+
* snapshots `delete()` never removes. Directory-only read (id, version count, last-modified
|
|
1122
|
+
* mtime) — no file content is opened here; that only happens once a specific version is
|
|
1123
|
+
* requested via `getVersionFile()`, which works for these ids too.
|
|
1124
|
+
*/
|
|
1125
|
+
listArchivedProfiles(): Promise<ArchivedProfileSummary[]>;
|
|
1126
|
+
/**
|
|
1127
|
+
* Seeds a default profile for a compliance group from the embedded English profile in
|
|
1128
|
+
* `@consenti/utils`, merged with locale text overlays for de/es/fr/ja. Every locale — including
|
|
1129
|
+
* non-English ones — is passed through `create()`'s normal `localeContent` path, the same as an
|
|
1130
|
+
* author-submitted profile; there is no separate "seeded profile" code path for locale content
|
|
1131
|
+
* anymore, which is what previously let a locale silently never make it into the served file.
|
|
1132
|
+
* Only creates the profile if no active profile already exists for the compliance group.
|
|
1133
|
+
* Safe to call repeatedly (idempotent).
|
|
1134
|
+
*
|
|
1135
|
+
* @param complianceGroup - One of the 8 compliance group IDs.
|
|
1136
|
+
*/
|
|
1137
|
+
seedDefaultProfile(complianceGroup: string): Promise<void>;
|
|
1138
|
+
/**
|
|
1139
|
+
* Seeds default profiles for all 8 compliance groups.
|
|
1140
|
+
* Skips any group that already has an active profile (idempotent).
|
|
1141
|
+
*/
|
|
1142
|
+
seedAllDefaults(): Promise<void>;
|
|
780
1143
|
}
|
|
781
1144
|
|
|
782
1145
|
declare class ConsentRepo {
|
|
@@ -786,7 +1149,7 @@ declare class ConsentRepo {
|
|
|
786
1149
|
update(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord>;
|
|
787
1150
|
delete(visitorId: string): Promise<void>;
|
|
788
1151
|
get(visitorId: string): Promise<ConsentDbRecord | null>;
|
|
789
|
-
list(filters: ConsentFilters): Promise<
|
|
1152
|
+
list(filters: ConsentFilters): Promise<PagedResult<ConsentSummary>>;
|
|
790
1153
|
}
|
|
791
1154
|
|
|
792
1155
|
declare class VisitorRepo {
|
|
@@ -822,7 +1185,20 @@ declare class ConsentService {
|
|
|
822
1185
|
private pluginEngine?;
|
|
823
1186
|
private eventBus?;
|
|
824
1187
|
private tcfConfig?;
|
|
825
|
-
|
|
1188
|
+
private storage?;
|
|
1189
|
+
private consentSigningKey?;
|
|
1190
|
+
constructor(consents: ConsentRepo, visitors: VisitorRepo, profiles: ProfileRepo, audit: AuditRepo, tenantId?: string, compliance?: ComplianceConfig | undefined, pluginEngine?: PluginEngine | undefined, eventBus?: EventEmitter | undefined, tcfConfig?: TcfConfig | undefined, storage?: StorageAdapter | undefined, consentSigningKey?: string | undefined);
|
|
1191
|
+
private sign;
|
|
1192
|
+
/**
|
|
1193
|
+
* Profiles created via the dashboard wizard reference a consent template (`consentTemplateId`)
|
|
1194
|
+
* rather than embedding `cookies`/`preferenceModal.categories` directly on `profileJson` — those
|
|
1195
|
+
* fields are only populated for the embedded/seeded default profiles (see
|
|
1196
|
+
* `ProfileService.seedDefaultProfile`). Cookie/category membership and `legalBasis` are
|
|
1197
|
+
* locale-independent, so the raw consent template's data is sufficient here — no need to
|
|
1198
|
+
* resolve per-locale text via `ProfileService.getResolved()`. Mirrors the same fallback
|
|
1199
|
+
* `ProfileService.getResolved()` and the admin route validators already apply.
|
|
1200
|
+
*/
|
|
1201
|
+
private resolveTemplateData;
|
|
826
1202
|
create(input: Omit<CreateConsentInput, 'tenantId'>): Promise<ConsentDbRecord>;
|
|
827
1203
|
update(visitorId: string, input: UpdateConsentInput): Promise<ConsentDbRecord>;
|
|
828
1204
|
get(visitorId: string): Promise<ConsentDbRecord | null>;
|
|
@@ -904,19 +1280,23 @@ declare class BetterSqlite3Adapter implements StorageAdapter {
|
|
|
904
1280
|
getProfiles(tenantId: string): Promise<Profile[]>;
|
|
905
1281
|
findActiveProfileByComplianceGroup(tenantId: string, complianceGroup: string): Promise<Profile | null>;
|
|
906
1282
|
private mapConsent;
|
|
1283
|
+
private static readonly CONSENT_SUMMARY_COLS;
|
|
1284
|
+
private mapConsentSummary;
|
|
907
1285
|
createConsent(data: CreateConsentInput): Promise<ConsentDbRecord>;
|
|
908
1286
|
updateConsent(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord>;
|
|
909
1287
|
deleteConsent(visitorId: string): Promise<void>;
|
|
910
1288
|
getConsent(visitorId: string): Promise<ConsentDbRecord | null>;
|
|
911
|
-
getConsents(filters: ConsentFilters): Promise<
|
|
1289
|
+
getConsents(filters: ConsentFilters): Promise<PagedResult<ConsentSummary>>;
|
|
912
1290
|
streamConsents(filters: ConsentFilters): AsyncIterable<ConsentDbRecord>;
|
|
913
1291
|
getConsentHistory(visitorId: string): Promise<ConsentHistoryEntry[]>;
|
|
1292
|
+
createNoticeShown(data: CreateNoticeShownInput): Promise<NoticeShownRecord>;
|
|
1293
|
+
getNoticeShownForVisitor(visitorId: string): Promise<NoticeShownRecord[]>;
|
|
914
1294
|
private mapVisitor;
|
|
915
1295
|
createVisitor(data: CreateVisitorInput): Promise<Visitor>;
|
|
916
1296
|
updateVisitor(visitorId: string, data: UpdateVisitorInput): Promise<Visitor>;
|
|
917
1297
|
deleteVisitor(visitorId: string): Promise<void>;
|
|
918
1298
|
getVisitor(visitorId: string): Promise<Visitor | null>;
|
|
919
|
-
getVisitors(filters: VisitorFilters): Promise<Visitor
|
|
1299
|
+
getVisitors(filters: VisitorFilters): Promise<PagedResult<Visitor>>;
|
|
920
1300
|
private mapUser;
|
|
921
1301
|
createUser(data: CreateUserInput): Promise<AdminUser>;
|
|
922
1302
|
updateUser(id: string, data: UpdateUserInput): Promise<AdminUser>;
|
|
@@ -937,7 +1317,10 @@ declare class BetterSqlite3Adapter implements StorageAdapter {
|
|
|
937
1317
|
assignRole(userId: string, roleId: string, tenantId?: string): Promise<void>;
|
|
938
1318
|
revokeRole(userId: string, roleId: string, tenantId?: string): Promise<void>;
|
|
939
1319
|
createLog(data: CreateAuditLogInput): Promise<void>;
|
|
940
|
-
getLogs(filters: AuditFilters): Promise<
|
|
1320
|
+
getLogs(filters: AuditFilters): Promise<PagedResult<AuditLogSummary>>;
|
|
1321
|
+
getAuditLogById(id: string): Promise<AuditLog | null>;
|
|
1322
|
+
private static readonly AUDIT_SUMMARY_COLS;
|
|
1323
|
+
private mapAuditSummary;
|
|
941
1324
|
private mapAuditLog;
|
|
942
1325
|
streamAuditLogs(filters: AuditFilters): AsyncIterable<AuditLog>;
|
|
943
1326
|
getOverviewStats(tenantId: string): Promise<OverviewStats>;
|
|
@@ -949,19 +1332,24 @@ declare class BetterSqlite3Adapter implements StorageAdapter {
|
|
|
949
1332
|
createTenant(data: CreateTenantInput): Promise<Tenant>;
|
|
950
1333
|
updateTenant(id: string, data: UpdateTenantInput): Promise<Tenant>;
|
|
951
1334
|
deleteTenant(id: string): Promise<void>;
|
|
1335
|
+
getSettings(tenantId: string): Promise<TenantSettings>;
|
|
1336
|
+
updateSettings(tenantId: string, data: Partial<TenantSettings>): Promise<TenantSettings>;
|
|
952
1337
|
purgeExpiredConsents(olderThanDays: number): Promise<number>;
|
|
1338
|
+
purgeExpiredAuditLogs(olderThanDays: number): Promise<number>;
|
|
953
1339
|
private mapApiKey;
|
|
954
1340
|
createApiKey(data: CreateApiKeyInput): Promise<ApiKey>;
|
|
955
1341
|
getApiKeyByHash(keyHash: string): Promise<ApiKey | null>;
|
|
956
1342
|
revokeApiKey(id: string): Promise<void>;
|
|
1343
|
+
reactivateApiKey(id: string): Promise<void>;
|
|
1344
|
+
deleteApiKey(id: string): Promise<void>;
|
|
957
1345
|
getApiKeys(tenantId: string): Promise<ApiKey[]>;
|
|
958
|
-
private
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
1346
|
+
private mapConsentTemplate;
|
|
1347
|
+
createConsentTemplate(data: CreateConsentTemplateInput): Promise<ServerConsentTemplate>;
|
|
1348
|
+
updateConsentTemplate(id: string, data: UpdateConsentTemplateInput): Promise<ServerConsentTemplate>;
|
|
1349
|
+
deleteConsentTemplate(id: string): Promise<void>;
|
|
1350
|
+
getConsentTemplate(id: string): Promise<ServerConsentTemplate | null>;
|
|
1351
|
+
getConsentTemplates(tenantId: string): Promise<ServerConsentTemplate[]>;
|
|
1352
|
+
copyConsentTemplate(id: string, newName: string): Promise<ServerConsentTemplate>;
|
|
965
1353
|
private mapUITemplate;
|
|
966
1354
|
createUITemplate(data: CreateUITemplateInput): Promise<ServerUITemplate>;
|
|
967
1355
|
updateUITemplate(id: string, data: UpdateUITemplateInput): Promise<ServerUITemplate>;
|
|
@@ -972,7 +1360,7 @@ declare class BetterSqlite3Adapter implements StorageAdapter {
|
|
|
972
1360
|
private mapProfileSummary;
|
|
973
1361
|
private readonly PROFILE_SUMMARY_SQL;
|
|
974
1362
|
listProfilesSummary(tenantId: string): Promise<ProfileSummary[]>;
|
|
975
|
-
|
|
1363
|
+
findProfilesUsingConsentTemplate(templateId: string): Promise<ProfileSummary[]>;
|
|
976
1364
|
findProfilesUsingUITemplate(templateId: string): Promise<ProfileSummary[]>;
|
|
977
1365
|
getOptInStats(tenantId: string, filters: OptInFilters): Promise<OptInStats>;
|
|
978
1366
|
}
|
|
@@ -998,16 +1386,18 @@ declare class MongoDBAdapter implements StorageAdapter {
|
|
|
998
1386
|
updateConsent(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord>;
|
|
999
1387
|
deleteConsent(visitorId: string): Promise<void>;
|
|
1000
1388
|
getConsent(visitorId: string): Promise<ConsentDbRecord | null>;
|
|
1001
|
-
getConsents(filters: ConsentFilters): Promise<
|
|
1389
|
+
getConsents(filters: ConsentFilters): Promise<PagedResult<ConsentSummary>>;
|
|
1002
1390
|
streamConsents(filters: ConsentFilters): AsyncIterable<ConsentDbRecord>;
|
|
1003
1391
|
private buildConsentFilter;
|
|
1004
1392
|
private writeHistory;
|
|
1005
1393
|
getConsentHistory(visitorId: string): Promise<ConsentHistoryEntry[]>;
|
|
1394
|
+
createNoticeShown(data: CreateNoticeShownInput): Promise<NoticeShownRecord>;
|
|
1395
|
+
getNoticeShownForVisitor(visitorId: string): Promise<NoticeShownRecord[]>;
|
|
1006
1396
|
createVisitor(data: CreateVisitorInput): Promise<Visitor>;
|
|
1007
1397
|
updateVisitor(visitorId: string, data: UpdateVisitorInput): Promise<Visitor>;
|
|
1008
1398
|
deleteVisitor(visitorId: string): Promise<void>;
|
|
1009
1399
|
getVisitor(visitorId: string): Promise<Visitor | null>;
|
|
1010
|
-
getVisitors(filters: VisitorFilters): Promise<Visitor
|
|
1400
|
+
getVisitors(filters: VisitorFilters): Promise<PagedResult<Visitor>>;
|
|
1011
1401
|
getOverviewStats(tenantId: string): Promise<OverviewStats>;
|
|
1012
1402
|
getCategoryStats(tenantId: string): Promise<CategoryStats>;
|
|
1013
1403
|
getTimeline(tenantId: string, days?: number): Promise<TimelineEntry[]>;
|
|
@@ -1030,26 +1420,33 @@ declare class MongoDBAdapter implements StorageAdapter {
|
|
|
1030
1420
|
assignPermissionToRole(roleId: string, permissionId: string): Promise<void>;
|
|
1031
1421
|
revokePermissionFromRole(roleId: string, permissionId: string): Promise<void>;
|
|
1032
1422
|
createLog(data: CreateAuditLogInput): Promise<void>;
|
|
1033
|
-
getLogs(filters: AuditFilters): Promise<
|
|
1423
|
+
getLogs(filters: AuditFilters): Promise<PagedResult<AuditLogSummary>>;
|
|
1424
|
+
getAuditLogById(id: string): Promise<AuditLog | null>;
|
|
1034
1425
|
streamAuditLogs(filters: AuditFilters): AsyncIterable<AuditLog>;
|
|
1035
1426
|
private buildAuditFilter;
|
|
1036
1427
|
getCountries(tenantId: string): Promise<CountryStat[]>;
|
|
1037
1428
|
getGpcStats(tenantId: string): Promise<GpcStats>;
|
|
1038
1429
|
getTenants(): Promise<Tenant[]>;
|
|
1430
|
+
private mapApiKey;
|
|
1039
1431
|
createApiKey(data: CreateApiKeyInput): Promise<ApiKey>;
|
|
1040
1432
|
getApiKeyByHash(keyHash: string): Promise<ApiKey | null>;
|
|
1041
1433
|
revokeApiKey(id: string): Promise<void>;
|
|
1434
|
+
reactivateApiKey(id: string): Promise<void>;
|
|
1435
|
+
deleteApiKey(id: string): Promise<void>;
|
|
1042
1436
|
getApiKeys(tenantId: string): Promise<ApiKey[]>;
|
|
1043
1437
|
createTenant(data: CreateTenantInput): Promise<Tenant>;
|
|
1044
1438
|
updateTenant(id: string, data: UpdateTenantInput): Promise<Tenant>;
|
|
1045
1439
|
deleteTenant(id: string): Promise<void>;
|
|
1440
|
+
getSettings(tenantId: string): Promise<TenantSettings>;
|
|
1441
|
+
updateSettings(tenantId: string, data: Partial<TenantSettings>): Promise<TenantSettings>;
|
|
1046
1442
|
purgeExpiredConsents(olderThanDays: number): Promise<number>;
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1443
|
+
purgeExpiredAuditLogs(olderThanDays: number): Promise<number>;
|
|
1444
|
+
createConsentTemplate(): Promise<never>;
|
|
1445
|
+
updateConsentTemplate(): Promise<never>;
|
|
1446
|
+
deleteConsentTemplate(): Promise<void>;
|
|
1447
|
+
getConsentTemplate(): Promise<never>;
|
|
1448
|
+
getConsentTemplates(): Promise<never>;
|
|
1449
|
+
copyConsentTemplate(): Promise<never>;
|
|
1053
1450
|
createUITemplate(): Promise<never>;
|
|
1054
1451
|
updateUITemplate(): Promise<never>;
|
|
1055
1452
|
deleteUITemplate(): Promise<void>;
|
|
@@ -1057,7 +1454,7 @@ declare class MongoDBAdapter implements StorageAdapter {
|
|
|
1057
1454
|
getUITemplates(): Promise<never>;
|
|
1058
1455
|
copyUITemplate(): Promise<never>;
|
|
1059
1456
|
listProfilesSummary(): Promise<never[]>;
|
|
1060
|
-
|
|
1457
|
+
findProfilesUsingConsentTemplate(): Promise<never[]>;
|
|
1061
1458
|
findProfilesUsingUITemplate(): Promise<never[]>;
|
|
1062
1459
|
getOptInStats(): Promise<never>;
|
|
1063
1460
|
}
|
|
@@ -1082,16 +1479,18 @@ declare class MySQLAdapter implements StorageAdapter {
|
|
|
1082
1479
|
updateConsent(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord>;
|
|
1083
1480
|
deleteConsent(visitorId: string): Promise<void>;
|
|
1084
1481
|
getConsent(visitorId: string): Promise<ConsentDbRecord | null>;
|
|
1085
|
-
getConsents(filters: ConsentFilters): Promise<
|
|
1482
|
+
getConsents(filters: ConsentFilters): Promise<PagedResult<ConsentSummary>>;
|
|
1086
1483
|
streamConsents(filters: ConsentFilters): AsyncIterable<ConsentDbRecord>;
|
|
1087
|
-
private
|
|
1484
|
+
private buildConsentWhere;
|
|
1088
1485
|
private writeHistory;
|
|
1089
1486
|
getConsentHistory(visitorId: string): Promise<ConsentHistoryEntry[]>;
|
|
1487
|
+
createNoticeShown(data: CreateNoticeShownInput): Promise<NoticeShownRecord>;
|
|
1488
|
+
getNoticeShownForVisitor(visitorId: string): Promise<NoticeShownRecord[]>;
|
|
1090
1489
|
createVisitor(data: CreateVisitorInput): Promise<Visitor>;
|
|
1091
1490
|
updateVisitor(visitorId: string, data: UpdateVisitorInput): Promise<Visitor>;
|
|
1092
1491
|
deleteVisitor(visitorId: string): Promise<void>;
|
|
1093
1492
|
getVisitor(visitorId: string): Promise<Visitor | null>;
|
|
1094
|
-
getVisitors(filters: VisitorFilters): Promise<Visitor
|
|
1493
|
+
getVisitors(filters: VisitorFilters): Promise<PagedResult<Visitor>>;
|
|
1095
1494
|
getOverviewStats(tenantId: string): Promise<OverviewStats>;
|
|
1096
1495
|
getCategoryStats(tenantId: string): Promise<CategoryStats>;
|
|
1097
1496
|
getTimeline(tenantId: string, days?: number): Promise<TimelineEntry[]>;
|
|
@@ -1114,26 +1513,33 @@ declare class MySQLAdapter implements StorageAdapter {
|
|
|
1114
1513
|
assignPermissionToRole(roleId: string, permissionId: string): Promise<void>;
|
|
1115
1514
|
revokePermissionFromRole(roleId: string, permissionId: string): Promise<void>;
|
|
1116
1515
|
createLog(data: CreateAuditLogInput): Promise<void>;
|
|
1117
|
-
getLogs(filters: AuditFilters): Promise<
|
|
1516
|
+
getLogs(filters: AuditFilters): Promise<PagedResult<AuditLogSummary>>;
|
|
1517
|
+
getAuditLogById(id: string): Promise<AuditLog | null>;
|
|
1118
1518
|
streamAuditLogs(filters: AuditFilters): AsyncIterable<AuditLog>;
|
|
1119
|
-
private
|
|
1519
|
+
private buildAuditWhere;
|
|
1120
1520
|
getCountries(tenantId: string): Promise<CountryStat[]>;
|
|
1121
1521
|
getGpcStats(tenantId: string): Promise<GpcStats>;
|
|
1122
1522
|
getTenants(): Promise<Tenant[]>;
|
|
1523
|
+
private mapApiKey;
|
|
1123
1524
|
createApiKey(data: CreateApiKeyInput): Promise<ApiKey>;
|
|
1124
1525
|
getApiKeyByHash(keyHash: string): Promise<ApiKey | null>;
|
|
1125
1526
|
revokeApiKey(id: string): Promise<void>;
|
|
1527
|
+
reactivateApiKey(id: string): Promise<void>;
|
|
1528
|
+
deleteApiKey(id: string): Promise<void>;
|
|
1126
1529
|
getApiKeys(tenantId: string): Promise<ApiKey[]>;
|
|
1127
1530
|
createTenant(data: CreateTenantInput): Promise<Tenant>;
|
|
1128
1531
|
updateTenant(id: string, data: UpdateTenantInput): Promise<Tenant>;
|
|
1532
|
+
getSettings(tenantId: string): Promise<TenantSettings>;
|
|
1533
|
+
updateSettings(tenantId: string, data: Partial<TenantSettings>): Promise<TenantSettings>;
|
|
1129
1534
|
deleteTenant(id: string): Promise<void>;
|
|
1130
1535
|
purgeExpiredConsents(olderThanDays: number): Promise<number>;
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1536
|
+
purgeExpiredAuditLogs(olderThanDays: number): Promise<number>;
|
|
1537
|
+
createConsentTemplate(): Promise<never>;
|
|
1538
|
+
updateConsentTemplate(): Promise<never>;
|
|
1539
|
+
deleteConsentTemplate(): Promise<void>;
|
|
1540
|
+
getConsentTemplate(): Promise<never>;
|
|
1541
|
+
getConsentTemplates(): Promise<never>;
|
|
1542
|
+
copyConsentTemplate(): Promise<never>;
|
|
1137
1543
|
createUITemplate(): Promise<never>;
|
|
1138
1544
|
updateUITemplate(): Promise<never>;
|
|
1139
1545
|
deleteUITemplate(): Promise<void>;
|
|
@@ -1141,7 +1547,7 @@ declare class MySQLAdapter implements StorageAdapter {
|
|
|
1141
1547
|
getUITemplates(): Promise<never>;
|
|
1142
1548
|
copyUITemplate(): Promise<never>;
|
|
1143
1549
|
listProfilesSummary(): Promise<never[]>;
|
|
1144
|
-
|
|
1550
|
+
findProfilesUsingConsentTemplate(): Promise<never[]>;
|
|
1145
1551
|
findProfilesUsingUITemplate(): Promise<never[]>;
|
|
1146
1552
|
getOptInStats(): Promise<never>;
|
|
1147
1553
|
}
|
|
@@ -1165,16 +1571,18 @@ declare class PostgreSQLAdapter implements StorageAdapter {
|
|
|
1165
1571
|
updateConsent(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord>;
|
|
1166
1572
|
deleteConsent(visitorId: string): Promise<void>;
|
|
1167
1573
|
getConsent(visitorId: string): Promise<ConsentDbRecord | null>;
|
|
1168
|
-
getConsents(filters: ConsentFilters): Promise<
|
|
1574
|
+
getConsents(filters: ConsentFilters): Promise<PagedResult<ConsentSummary>>;
|
|
1169
1575
|
streamConsents(filters: ConsentFilters): AsyncIterable<ConsentDbRecord>;
|
|
1170
|
-
private
|
|
1576
|
+
private buildConsentWhere;
|
|
1171
1577
|
private writeHistory;
|
|
1172
1578
|
getConsentHistory(visitorId: string): Promise<ConsentHistoryEntry[]>;
|
|
1579
|
+
createNoticeShown(data: CreateNoticeShownInput): Promise<NoticeShownRecord>;
|
|
1580
|
+
getNoticeShownForVisitor(visitorId: string): Promise<NoticeShownRecord[]>;
|
|
1173
1581
|
createVisitor(data: CreateVisitorInput): Promise<Visitor>;
|
|
1174
1582
|
updateVisitor(visitorId: string, data: UpdateVisitorInput): Promise<Visitor>;
|
|
1175
1583
|
deleteVisitor(visitorId: string): Promise<void>;
|
|
1176
1584
|
getVisitor(visitorId: string): Promise<Visitor | null>;
|
|
1177
|
-
getVisitors(filters: VisitorFilters): Promise<Visitor
|
|
1585
|
+
getVisitors(filters: VisitorFilters): Promise<PagedResult<Visitor>>;
|
|
1178
1586
|
getOverviewStats(tenantId: string): Promise<OverviewStats>;
|
|
1179
1587
|
getCategoryStats(tenantId: string): Promise<CategoryStats>;
|
|
1180
1588
|
getTimeline(tenantId: string, days?: number): Promise<TimelineEntry[]>;
|
|
@@ -1197,26 +1605,33 @@ declare class PostgreSQLAdapter implements StorageAdapter {
|
|
|
1197
1605
|
assignPermissionToRole(roleId: string, permissionId: string): Promise<void>;
|
|
1198
1606
|
revokePermissionFromRole(roleId: string, permissionId: string): Promise<void>;
|
|
1199
1607
|
createLog(data: CreateAuditLogInput): Promise<void>;
|
|
1200
|
-
getLogs(filters: AuditFilters): Promise<
|
|
1608
|
+
getLogs(filters: AuditFilters): Promise<PagedResult<AuditLogSummary>>;
|
|
1609
|
+
getAuditLogById(id: string): Promise<AuditLog | null>;
|
|
1201
1610
|
streamAuditLogs(filters: AuditFilters): AsyncIterable<AuditLog>;
|
|
1202
|
-
private
|
|
1611
|
+
private buildAuditWhere;
|
|
1203
1612
|
getCountries(tenantId: string): Promise<CountryStat[]>;
|
|
1204
1613
|
getGpcStats(tenantId: string): Promise<GpcStats>;
|
|
1205
1614
|
getTenants(): Promise<Tenant[]>;
|
|
1615
|
+
private mapApiKey;
|
|
1206
1616
|
createApiKey(data: CreateApiKeyInput): Promise<ApiKey>;
|
|
1207
1617
|
getApiKeyByHash(keyHash: string): Promise<ApiKey | null>;
|
|
1208
1618
|
revokeApiKey(id: string): Promise<void>;
|
|
1619
|
+
reactivateApiKey(id: string): Promise<void>;
|
|
1620
|
+
deleteApiKey(id: string): Promise<void>;
|
|
1209
1621
|
getApiKeys(tenantId: string): Promise<ApiKey[]>;
|
|
1210
1622
|
createTenant(data: CreateTenantInput): Promise<Tenant>;
|
|
1211
1623
|
updateTenant(id: string, data: UpdateTenantInput): Promise<Tenant>;
|
|
1212
1624
|
deleteTenant(id: string): Promise<void>;
|
|
1625
|
+
getSettings(tenantId: string): Promise<TenantSettings>;
|
|
1626
|
+
updateSettings(tenantId: string, data: Partial<TenantSettings>): Promise<TenantSettings>;
|
|
1213
1627
|
purgeExpiredConsents(olderThanDays: number): Promise<number>;
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1628
|
+
purgeExpiredAuditLogs(olderThanDays: number): Promise<number>;
|
|
1629
|
+
createConsentTemplate(): Promise<never>;
|
|
1630
|
+
updateConsentTemplate(): Promise<never>;
|
|
1631
|
+
deleteConsentTemplate(): Promise<void>;
|
|
1632
|
+
getConsentTemplate(): Promise<never>;
|
|
1633
|
+
getConsentTemplates(): Promise<never>;
|
|
1634
|
+
copyConsentTemplate(): Promise<never>;
|
|
1220
1635
|
createUITemplate(): Promise<never>;
|
|
1221
1636
|
updateUITemplate(): Promise<never>;
|
|
1222
1637
|
deleteUITemplate(): Promise<void>;
|
|
@@ -1224,11 +1639,131 @@ declare class PostgreSQLAdapter implements StorageAdapter {
|
|
|
1224
1639
|
getUITemplates(): Promise<never>;
|
|
1225
1640
|
copyUITemplate(): Promise<never>;
|
|
1226
1641
|
listProfilesSummary(): Promise<never[]>;
|
|
1227
|
-
|
|
1642
|
+
findProfilesUsingConsentTemplate(): Promise<never[]>;
|
|
1228
1643
|
findProfilesUsingUITemplate(): Promise<never[]>;
|
|
1229
1644
|
getOptInStats(): Promise<never>;
|
|
1230
1645
|
}
|
|
1231
1646
|
|
|
1647
|
+
/**
|
|
1648
|
+
* ConsentAction — server-side counterpart to `@consenti/ui`'s `ConsentAction`.
|
|
1649
|
+
*
|
|
1650
|
+
* Watches a single consent parameter across *every* visitor's submission (not just one
|
|
1651
|
+
* browser's own state) and fires `onGrant`/`onDeny` when that parameter's status actually
|
|
1652
|
+
* changes — via the same `eventBus` `createConsenti()` already emits `consent.created`/
|
|
1653
|
+
* `consent.updated` on. Useful for server-side integrations (CRM sync, suppression lists,
|
|
1654
|
+
* downstream webhooks) that need to react to consent decisions without polling the database.
|
|
1655
|
+
*
|
|
1656
|
+
* There is no server equivalent of the widget's `ConsentScript` — injecting a `<script>` tag
|
|
1657
|
+
* only makes sense in a browser DOM the server doesn't have. `services.consent.create()`/
|
|
1658
|
+
* `.update()` are already the server-side "submit"/"update consent" methods this hook reacts to.
|
|
1659
|
+
*
|
|
1660
|
+
* @example
|
|
1661
|
+
* ```ts
|
|
1662
|
+
* import { createConsenti, ConsentAction } from '@consenti/api'
|
|
1663
|
+
*
|
|
1664
|
+
* const { eventBus } = createConsenti({ ... })
|
|
1665
|
+
*
|
|
1666
|
+
* new ConsentAction({
|
|
1667
|
+
* id: 'analytics_storage',
|
|
1668
|
+
* eventBus,
|
|
1669
|
+
* onGrant: ({ visitorId }) => crm.optIn(visitorId),
|
|
1670
|
+
* onDeny: ({ visitorId }) => crm.optOut(visitorId),
|
|
1671
|
+
* })
|
|
1672
|
+
* ```
|
|
1673
|
+
*/
|
|
1674
|
+
|
|
1675
|
+
/** Passed to `onGrant`/`onDeny` — the transitioning parameter's status plus the full consent record. */
|
|
1676
|
+
interface ConsentActionParams {
|
|
1677
|
+
visitorId: string;
|
|
1678
|
+
cookieId: string;
|
|
1679
|
+
status: ConsentStatus;
|
|
1680
|
+
record: ConsentDbRecord;
|
|
1681
|
+
}
|
|
1682
|
+
/** Options for constructing a {@link ConsentAction} instance. */
|
|
1683
|
+
interface ConsentActionOptions {
|
|
1684
|
+
/** The consent parameter ID to watch (e.g. `'analytics_storage'`). */
|
|
1685
|
+
id: string;
|
|
1686
|
+
/** The `eventBus` returned by `createConsenti()`. */
|
|
1687
|
+
eventBus: EventEmitter;
|
|
1688
|
+
/** Called when the parameter's status transitions to `'granted'`, for any visitor. */
|
|
1689
|
+
onGrant?: (params: ConsentActionParams) => void;
|
|
1690
|
+
/** Called when the parameter's status transitions away from `'granted'` (`'denied'` or `'objected'`). */
|
|
1691
|
+
onDeny?: (params: ConsentActionParams) => void;
|
|
1692
|
+
}
|
|
1693
|
+
/**
|
|
1694
|
+
* Watches a single consent parameter across every incoming `consent.created`/`consent.updated`
|
|
1695
|
+
* event and fires `onGrant`/`onDeny` on transitions. Call {@link ConsentAction.destroy} to
|
|
1696
|
+
* remove the event listeners when the hook is no longer needed.
|
|
1697
|
+
*/
|
|
1698
|
+
declare class ConsentAction {
|
|
1699
|
+
private readonly options;
|
|
1700
|
+
private readonly onCreated;
|
|
1701
|
+
private readonly onUpdated;
|
|
1702
|
+
constructor(options: ConsentActionOptions);
|
|
1703
|
+
private fire;
|
|
1704
|
+
/** Removes the event listeners. Call when the hook is no longer needed. */
|
|
1705
|
+
destroy(): void;
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
/**
|
|
1709
|
+
* CategoryAction — server-side counterpart to `@consenti/ui`'s `CategoryAction`.
|
|
1710
|
+
*
|
|
1711
|
+
* Same idea as {@link ConsentAction} but watches a whole category's rollup consent state
|
|
1712
|
+
* (granted only when *every* cookie in the category is granted) instead of one parameter —
|
|
1713
|
+
* matching the preference modal's tri-state rollup rule and the widget's `CategoryAction`.
|
|
1714
|
+
*
|
|
1715
|
+
* @example
|
|
1716
|
+
* ```ts
|
|
1717
|
+
* import { createConsenti, CategoryAction } from '@consenti/api'
|
|
1718
|
+
*
|
|
1719
|
+
* const { eventBus, services } = createConsenti({ ... })
|
|
1720
|
+
*
|
|
1721
|
+
* new CategoryAction({
|
|
1722
|
+
* categoryId: 'marketing',
|
|
1723
|
+
* eventBus,
|
|
1724
|
+
* profiles: services.profile,
|
|
1725
|
+
* onGrant: ({ visitorId }) => adsPlatform.optIn(visitorId),
|
|
1726
|
+
* onDeny: ({ visitorId }) => adsPlatform.optOut(visitorId),
|
|
1727
|
+
* })
|
|
1728
|
+
* ```
|
|
1729
|
+
*/
|
|
1730
|
+
|
|
1731
|
+
/** Passed to `onGrant`/`onDeny` — the category's rollup status plus the full consent record. */
|
|
1732
|
+
interface CategoryActionParams {
|
|
1733
|
+
visitorId: string;
|
|
1734
|
+
categoryId: string;
|
|
1735
|
+
status: ConsentStatus;
|
|
1736
|
+
record: ConsentDbRecord;
|
|
1737
|
+
}
|
|
1738
|
+
/** Options for constructing a {@link CategoryAction} instance. */
|
|
1739
|
+
interface CategoryActionOptions {
|
|
1740
|
+
/** The category ID to watch (e.g. `'marketing'`). */
|
|
1741
|
+
categoryId: string;
|
|
1742
|
+
/** The `eventBus` returned by `createConsenti()`. */
|
|
1743
|
+
eventBus: EventEmitter;
|
|
1744
|
+
/** The `services.profile` returned by `createConsenti()` — resolves which cookies belong to
|
|
1745
|
+
* this category for the record's profile (categories are defined on the consent template). */
|
|
1746
|
+
profiles: ProfileService;
|
|
1747
|
+
/** Called when every cookie in the category transitions to `'granted'`. */
|
|
1748
|
+
onGrant?: (params: CategoryActionParams) => void;
|
|
1749
|
+
/** Called when the category transitions away from fully granted. */
|
|
1750
|
+
onDeny?: (params: CategoryActionParams) => void;
|
|
1751
|
+
}
|
|
1752
|
+
/**
|
|
1753
|
+
* Watches a category's rollup consent status across every incoming `consent.created`/
|
|
1754
|
+
* `consent.updated` event and fires `onGrant`/`onDeny` on transitions. Call
|
|
1755
|
+
* {@link CategoryAction.destroy} to remove the event listeners when no longer needed.
|
|
1756
|
+
*/
|
|
1757
|
+
declare class CategoryAction {
|
|
1758
|
+
private readonly options;
|
|
1759
|
+
private readonly onCreated;
|
|
1760
|
+
private readonly onUpdated;
|
|
1761
|
+
constructor(options: CategoryActionOptions);
|
|
1762
|
+
private fire;
|
|
1763
|
+
/** Removes the event listeners. Call when the hook is no longer needed. */
|
|
1764
|
+
destroy(): void;
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1232
1767
|
declare const dashboardDir: string;
|
|
1233
1768
|
declare function createConsenti(userConfig: ConsentiServerConfig): {
|
|
1234
1769
|
router: (req: IncomingMessage, res: ServerResponse, next: (err?: unknown) => void) => void;
|
|
@@ -1256,4 +1791,4 @@ declare function createConsenti(userConfig: ConsentiServerConfig): {
|
|
|
1256
1791
|
destroy: () => Promise<void>;
|
|
1257
1792
|
};
|
|
1258
1793
|
|
|
1259
|
-
export { type AdminUser, type AuditLog, type BrandingConfig, type ConsentDbRecord, type ConsentVerifyResult, type ConsentiServerConfig, MongoDBAdapter, MySQLAdapter, type Permission, PostgreSQLAdapter, type Profile, type Role, BetterSqlite3Adapter as SQLiteAdapter, type SafeAdminUser, type StorageAdapter, type Visitor, createConsenti, dashboardDir };
|
|
1794
|
+
export { type AdminUser, type AuditLog, type BrandingConfig, CategoryAction, type CategoryActionOptions, type CategoryActionParams, ConsentAction, type ConsentActionOptions, type ConsentActionParams, type ConsentDbRecord, type ConsentVerifyResult, type ConsentiServerConfig, MongoDBAdapter, MySQLAdapter, type Permission, PostgreSQLAdapter, type Profile, type Role, BetterSqlite3Adapter as SQLiteAdapter, type SafeAdminUser, type StorageAdapter, type Visitor, createConsenti, dashboardDir };
|