@consenti/api 0.1.0 → 0.2.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 +608 -195
- package/dist/dashboard/assets/de-DwE2aQfW.js +5 -0
- package/dist/dashboard/assets/es-Dq88TWkB.js +5 -0
- package/dist/dashboard/assets/fr-o_Pyg8eR.js +5 -0
- package/dist/dashboard/assets/index-BSsYDdb9.js +40 -0
- package/dist/dashboard/assets/index-bOTGevzl.css +2 -0
- package/dist/dashboard/assets/ja-CwgXYmpD.js +5 -0
- package/dist/dashboard/assets/zh-CN-ety9KoQ0.js +5 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/index.cjs +135 -9084
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +369 -195
- package/dist/index.d.ts +369 -195
- package/dist/index.js +135 -9038
- package/dist/index.js.map +1 -1
- package/dist/widget/widget.css +1 -0
- package/dist/widget/widget.js +1 -2304
- package/package.json +16 -9
- package/dist/dashboard/assets/index-BBbhHyc_.js +0 -2637
- package/dist/dashboard/assets/index-DYK73WL5.css +0 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../../../node_modules/tsup/assets/cjs_shims.js","../src/core/plugin-engine.ts","../src/tcf/gvl-cache.ts","../src/openapi/spec.ts","../src/utils/crypto.ts","../src/storage/seed-data.ts","../src/storage/sqlite/better-sqlite3.adapter.ts","../src/storage/sqlite/node-sqlite3-wasm.adapter.ts","../src/storage/sqlite/node-sqlite-builtin.adapter.ts","../src/storage/mongodb/mongodb.adapter.ts","../src/storage/mysql/mysql.adapter.ts","../src/storage/postgresql/postgresql.adapter.ts","../src/storage/json/json-file.adapter.ts","../src/repositories/profile.repo.ts","../src/repositories/consent.repo.ts","../src/repositories/visitor.repo.ts","../src/repositories/audit.repo.ts","../src/repositories/user.repo.ts","../src/core/profile-engine.ts","../src/services/profile.service.ts","../src/core/consent-engine.ts","../src/tcf/tc-string.ts","../src/services/consent.service.ts","../src/services/visitor.service.ts","../src/services/user.service.ts","../src/auth/local.auth.ts","../src/utils/http.ts","../src/middleware/error.middleware.ts","../src/routes/public/profile.routes.ts","../src/utils/cookie.ts","../src/middleware/cors.middleware.ts","../src/validators/consent.validator.ts","../src/routes/public/consent.routes.ts","../src/routes/admin/auth.routes.ts","../src/middleware/auth.middleware.ts","../src/auth/oidc.auth.ts","../src/auth/saml.auth.ts","../src/auth/totp.ts","../src/validators/profile.validator.ts","../src/routes/admin/profiles.routes.ts","../src/routes/admin/consents.routes.ts","../src/routes/admin/visitors.routes.ts","../src/routes/admin/users.routes.ts","../src/routes/admin/roles.routes.ts","../src/routes/admin/audit.routes.ts","../src/routes/admin/stats.routes.ts","../src/routes/admin/export.routes.ts","../src/routes/admin/apikeys.routes.ts","../src/routes/admin/tenants.routes.ts","../src/routes/admin/tcf.routes.ts","../src/routes/admin/cookie-templates.routes.ts","../src/routes/admin/ui-templates.routes.ts","../src/middleware/tenant.middleware.ts","../src/middleware/rate-limit.middleware.ts"],"sourcesContent":["import { EventEmitter } from 'node:events'\nimport { readFile } from 'node:fs/promises'\nimport { join, extname, dirname } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { PluginEngine } from './core/plugin-engine'\nimport { startGvlRefresh, stopGvlRefresh } from './tcf/gvl-cache'\nimport { OPENAPI_PUBLIC_SPEC, OPENAPI_ADMIN_SPEC } from './openapi/spec'\nimport { BetterSqlite3Adapter } from './storage/sqlite/better-sqlite3.adapter'\nimport { NodeSqlite3WasmAdapter } from './storage/sqlite/node-sqlite3-wasm.adapter'\nimport { NodeSqliteBuiltinAdapter } from './storage/sqlite/node-sqlite-builtin.adapter'\nimport { MongoDBAdapter } from './storage/mongodb/mongodb.adapter'\nimport { MySQLAdapter } from './storage/mysql/mysql.adapter'\nimport { PostgreSQLAdapter } from './storage/postgresql/postgresql.adapter'\nimport { JsonFileAdapter } from './storage/json/json-file.adapter'\nimport { ProfileRepo } from './repositories/profile.repo'\nimport { ConsentRepo } from './repositories/consent.repo'\nimport { VisitorRepo } from './repositories/visitor.repo'\nimport { AuditRepo } from './repositories/audit.repo'\nimport { UserRepo } from './repositories/user.repo'\nimport { ProfileService } from './services/profile.service'\nimport { ConsentService } from './services/consent.service'\nimport { VisitorService } from './services/visitor.service'\nimport { UserService } from './services/user.service'\nimport { LocalAuth } from './auth/local.auth'\nimport { buildProfileRoutes } from './routes/public/profile.routes'\nimport { buildConsentRoutes } from './routes/public/consent.routes'\nimport { buildAdminAuthRoutes } from './routes/admin/auth.routes'\nimport { buildAdminProfileRoutes } from './routes/admin/profiles.routes'\nimport { buildAdminConsentRoutes } from './routes/admin/consents.routes'\nimport { buildAdminVisitorRoutes } from './routes/admin/visitors.routes'\nimport { buildAdminUserRoutes } from './routes/admin/users.routes'\nimport { buildAdminRoleRoutes } from './routes/admin/roles.routes'\nimport { buildAdminAuditRoutes } from './routes/admin/audit.routes'\nimport { buildAdminStatsRoutes } from './routes/admin/stats.routes'\nimport { buildAdminExportRoutes } from './routes/admin/export.routes'\nimport { buildAdminApiKeyRoutes } from './routes/admin/apikeys.routes'\nimport { buildAdminTenantRoutes } from './routes/admin/tenants.routes'\nimport { buildAdminTcfRoutes } from './routes/admin/tcf.routes'\nimport { buildAdminCookieTemplateRoutes } from './routes/admin/cookie-templates.routes'\nimport { buildAdminUITemplateRoutes } from './routes/admin/ui-templates.routes'\nimport { resolveTenant } from './middleware/tenant.middleware'\nimport { RateLimiter } from './middleware/rate-limit.middleware'\nimport { handleCors, withCors, addSecurityHeaders } from './middleware/cors.middleware'\nimport { errorResponse } from './middleware/error.middleware'\nimport { nodeRequestToFetch, fetchResponseToNode, PayloadTooLargeError } from './utils/http'\nimport type { ConsentiServerConfig, StorageAdapter, StorageConfig } from '@consenti/types'\nimport type { IncomingMessage, ServerResponse } from 'node:http'\n\n// ── Path resolution ────────────────────────────────────────────────────────────\n\nconst DIST_DIR = dirname(fileURLToPath(import.meta.url))\n// new URL pattern is recognised by @vercel/nft (Next.js standalone tracer),\n// causing it to include the dashboard/ directory for any consumer's standalone build.\nexport const dashboardDir: string = fileURLToPath(new URL('./dashboard', import.meta.url))\n\nconst MIME: Record<string, string> = {\n '.html': 'text/html; charset=utf-8',\n '.js': 'application/javascript; charset=utf-8',\n '.mjs': 'application/javascript; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.json': 'application/json',\n '.png': 'image/png',\n '.svg': 'image/svg+xml',\n '.ico': 'image/x-icon',\n '.woff2': 'font/woff2',\n '.woff': 'font/woff',\n '.ttf': 'font/ttf',\n}\n\nasync function tryServeDashboard(\n pathname: string,\n basePath: string,\n dashboardDir: string,\n res: ServerResponse,\n): Promise<boolean> {\n const rel = pathname.slice(basePath.length) || '/'\n if (rel.startsWith('/api/') || rel.startsWith('/admin/')) return false\n const target = rel === '/' || rel === '' || !extname(rel)\n ? join(dashboardDir, 'index.html')\n : join(dashboardDir, rel)\n // directory traversal guard\n if (!target.startsWith(dashboardDir)) return false\n try {\n const data = await readFile(target)\n const ct = MIME[extname(target).toLowerCase()] ?? 'application/octet-stream'\n res.writeHead(200, { 'Content-Type': ct })\n res.end(data)\n return true\n } catch {\n return false\n }\n}\n\nasync function serveDistFile(filePath: string, contentType: string): Promise<Response> {\n try {\n const data = await readFile(filePath)\n return new Response(data, { headers: { 'Content-Type': contentType, 'Cache-Control': 'public, max-age=3600' } })\n } catch {\n return new Response('Not Found', { status: 404 })\n }\n}\n\n// ── Minimal path router ────────────────────────────────────────────────────────\n\ntype Handler = (req: Request, params: Record<string, string>) => Promise<Response>\n\ninterface RouteEntry {\n method: string\n pattern: RegExp\n paramNames: string[]\n handler: Handler\n rateLimit: boolean\n}\n\nfunction compilePath(path: string): { pattern: RegExp; paramNames: string[] } {\n const paramNames: string[] = []\n const regexParts = path.split('/').map(part => {\n if (part.startsWith(':')) {\n paramNames.push(part.slice(1))\n return '([^/]+)'\n }\n return part.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n })\n return { pattern: new RegExp(`^${regexParts.join('\\\\/')}$`), paramNames }\n}\n\ninterface RouteGroup {\n prefix: string\n routes: Record<string, Handler>\n rateLimit?: boolean\n}\n\nfunction branded404(basePath: string): Response {\n const docsHref = `${basePath}/api/docs`\n const html = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<title>404 — Consenti</title>\n<style>\n *{box-sizing:border-box;margin:0;padding:0}\n body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:#0f1117;color:#e2e8f0;min-height:100vh;display:flex;align-items:center;justify-content:center;padding:2rem}\n .card{text-align:center;max-width:480px;width:100%}\n .badge{display:inline-flex;align-items:center;gap:.5rem;background:#1e2330;border:1px solid #2d3347;border-radius:999px;padding:.35rem .85rem;font-size:.75rem;letter-spacing:.08em;text-transform:uppercase;color:#7c8db5;margin-bottom:2rem}\n .badge svg{width:14px;height:14px;fill:#4f6ef7}\n h1{font-size:6rem;font-weight:800;line-height:1;background:linear-gradient(135deg,#4f6ef7,#a78bfa);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;margin-bottom:.5rem}\n h2{font-size:1.25rem;font-weight:600;color:#cbd5e1;margin-bottom:.75rem}\n p{font-size:.9rem;color:#64748b;line-height:1.6;margin-bottom:2rem}\n a{display:inline-flex;align-items:center;gap:.4rem;background:#4f6ef7;color:#fff;text-decoration:none;padding:.6rem 1.25rem;border-radius:.5rem;font-size:.875rem;font-weight:500;transition:background .15s}\n a:hover{background:#3b5ce6}\n a svg{width:14px;height:14px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}\n</style>\n</head>\n<body>\n<div class=\"card\">\n <div class=\"badge\">\n <svg viewBox=\"0 0 16 16\"><path d=\"M8 1a7 7 0 100 14A7 7 0 008 1zm0 3a1 1 0 110 2 1 1 0 010-2zm1 7H7V7h2v4z\"/></svg>\n Consenti\n </div>\n <h1>404</h1>\n <h2>Page not found</h2>\n <p>The admin dashboard is not enabled on this instance.<br>Use the API or enable <code style=\"background:#1e2330;padding:.1rem .35rem;border-radius:.25rem;font-size:.8rem\">dashboard: true</code> in your config.</p>\n <a href=\"${docsHref}\">\n <svg viewBox=\"0 0 24 24\"><path d=\"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z\"/><polyline points=\"14 2 14 8 20 8\"/><line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\"/><line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\"/><polyline points=\"10 9 9 9 8 9\"/></svg>\n View API Documentation\n </a>\n</div>\n</body>\n</html>`\n return new Response(html, { status: 404, headers: { 'Content-Type': 'text/html; charset=utf-8' } })\n}\n\nfunction buildFetchRouter(\n basePath: string,\n groups: RouteGroup[],\n rateLimiter: RateLimiter | null,\n): (request: Request) => Promise<Response> {\n const entries: RouteEntry[] = []\n\n for (const group of groups) {\n for (const [key, handler] of Object.entries(group.routes)) {\n const spaceIdx = key.indexOf(' ')\n const method = key.slice(0, spaceIdx).toUpperCase()\n const path = key.slice(spaceIdx + 1)\n const { pattern, paramNames } = compilePath(`${group.prefix}${path}`)\n entries.push({ method, pattern, paramNames, handler, rateLimit: group.rateLimit ?? false })\n }\n }\n\n return async (request: Request): Promise<Response> => {\n const corsResponse = handleCors(request)\n if (corsResponse) return corsResponse\n\n const url = new URL(request.url)\n const pathname = url.pathname\n const method = request.method.toUpperCase()\n\n if (rateLimiter) {\n const matched = entries.find(e => e.rateLimit && pathname.match(e.pattern))\n if (matched) {\n const ip = request.headers.get('x-real-ip') ?? ''\n if (!rateLimiter.checkRequest(ip)) {\n return withCors(errorResponse(429, 'Too Many Requests'), request)\n }\n }\n }\n\n for (const entry of entries) {\n if (entry.method !== method) continue\n const match = pathname.match(entry.pattern)\n if (!match) continue\n const params: Record<string, string> = {}\n entry.paramNames.forEach((name, i) => {\n const val = match[i + 1]\n if (val != null) params[name] = val\n })\n const response = await entry.handler(request, params)\n return addSecurityHeaders(withCors(response, request))\n }\n\n const isUiPath =\n pathname.startsWith(basePath) &&\n !pathname.startsWith(`${basePath}/api/`) &&\n !pathname.startsWith(`${basePath}/admin/`)\n\n return addSecurityHeaders(\n withCors(isUiPath ? branded404(basePath) : errorResponse(404, 'Not Found'), request),\n )\n }\n}\n\n// ── Deep merge ────────────────────────────────────────────────────────────────\n\nfunction isPlainObj(v: unknown): v is Record<string, unknown> {\n return typeof v === 'object' && v !== null && !Array.isArray(v)\n}\n\nfunction deepMerge(\n base: Record<string, unknown>,\n override: Record<string, unknown>,\n): Record<string, unknown> {\n const result: Record<string, unknown> = { ...base }\n for (const key of Object.keys(override)) {\n const ov = override[key]\n const bv = result[key]\n if (ov !== undefined && isPlainObj(ov) && isPlainObj(bv)) {\n result[key] = deepMerge(bv, ov)\n } else if (ov !== undefined) {\n result[key] = ov\n }\n }\n return result\n}\n\n// ── Default config ────────────────────────────────────────────────────────────\n\nconst DEFAULT_CONFIG: ConsentiServerConfig = {\n dashboard: true,\n basePath: process.env['CONSENTI_BASE_PATH'] ?? '/consenti',\n ...(process.env['CONSENTI_MAX_BODY_SIZE'] ? { maxBodySize: Number(process.env['CONSENTI_MAX_BODY_SIZE']) } : {}),\n storage: {\n driver: (process.env['CONSENTI_DB_DRIVER'] as StorageConfig['driver'] | undefined) ?? 'json',\n path: process.env['CONSENTI_DB_PATH'] ?? './consenti-data.json',\n ...(process.env['CONSENTI_DB_URI'] ? { uri: process.env['CONSENTI_DB_URI'] } : {}),\n ...(process.env['CONSENTI_DB_NAME'] ? { dbName: process.env['CONSENTI_DB_NAME'] } : {}),\n ...(process.env['CONSENTI_DB_DATABASE'] ? { database: process.env['CONSENTI_DB_DATABASE'] } : {}),\n ...(process.env['CONSENTI_DB_HOST'] ? { host: process.env['CONSENTI_DB_HOST'] } : {}),\n ...(process.env['CONSENTI_DB_PORT'] ? { port: Number(process.env['CONSENTI_DB_PORT']) } : {}),\n ...(process.env['CONSENTI_DB_USER'] ? { user: process.env['CONSENTI_DB_USER'] } : {}),\n ...(process.env['CONSENTI_DB_PASSWORD'] ? { password: process.env['CONSENTI_DB_PASSWORD'] } : {}),\n },\n auth: {\n mode: 'local',\n adminEmail: process.env['CONSENTI_ADMIN_EMAIL'] ?? 'user@consenti.dev',\n adminPassword: process.env['CONSENTI_ADMIN_PASSWORD'] ?? 'Consenti@123',\n ...(process.env['CONSENTI_ADMIN_JWT_SECRET'] ? { jwtSecret: process.env['CONSENTI_ADMIN_JWT_SECRET'] } : {}),\n },\n rateLimit: {\n windowMs: process.env['CONSENTI_RATE_LIMIT_WINDOW_MS'] ? Number(process.env['CONSENTI_RATE_LIMIT_WINDOW_MS']) : 60_000,\n maxRequests: process.env['CONSENTI_RATE_LIMIT_MAX_REQUESTS'] ? Number(process.env['CONSENTI_RATE_LIMIT_MAX_REQUESTS']) : 60,\n },\n}\n\n// ── Factory ────────────────────────────────────────────────────────────────────\n\nfunction createStorageAdapter(config: NonNullable<ConsentiServerConfig['storage']>): StorageAdapter {\n switch (config.driver) {\n case 'mongodb': return new MongoDBAdapter(config)\n case 'mysql': return new MySQLAdapter(config)\n case 'postgresql': return new PostgreSQLAdapter(config)\n case 'node:sqlite': return new NodeSqliteBuiltinAdapter(config)\n case 'better-sqlite3':\n case 'sqlite': return new BetterSqlite3Adapter(config)\n case 'node-sqlite3-wasm': new NodeSqlite3WasmAdapter(config)\n case 'json':\n default: return new JsonFileAdapter(config)\n }\n}\n\nexport function createConsenti(userConfig: ConsentiServerConfig) {\n const config = deepMerge(\n DEFAULT_CONFIG as unknown as Record<string, unknown>,\n userConfig as unknown as Record<string, unknown>,\n ) as ConsentiServerConfig\n\n if (!userConfig.storage) {\n console.warn('[Consenti] No storage config — using node-sqlite3-wasm (SQLite WASM) at ./consenti-data.db. Switch to a database driver for production.')\n }\n if (!userConfig.auth && !process.env['CONSENTI_ADMIN_PASSWORD']) {\n console.warn('[Consenti] No auth config or CONSENTI_ADMIN_PASSWORD env var — using demo credentials. Set CONSENTI_ADMIN_EMAIL and CONSENTI_ADMIN_PASSWORD before going to production.')\n }\n\n const storageConfig = config.storage!\n const authConfig = config.auth!\n\n const storage = createStorageAdapter(storageConfig)\n const eventBus = new EventEmitter()\n\n const profileRepo = new ProfileRepo(storage)\n const consentRepo = new ConsentRepo(storage)\n const visitorRepo = new VisitorRepo(storage)\n const auditRepo = new AuditRepo(storage)\n const userRepo = new UserRepo(storage)\n\n const pluginEngine = new PluginEngine()\n if (config.plugins?.length) pluginEngine.register(config.plugins)\n\n const profileService = new ProfileService(profileRepo, auditRepo, 'default', storage)\n const visitorService = new VisitorService(visitorRepo)\n const consentService = new ConsentService(\n consentRepo, visitorRepo, profileRepo, auditRepo, 'default', config.compliance,\n pluginEngine, eventBus, config.tcf,\n )\n const userService = new UserService(userRepo, auditRepo)\n\n const adminSecret = authConfig.jwtSecret ?? ''\n const localAuth = new LocalAuth(storage, adminSecret)\n\n const rl = config.rateLimit!\n const rateLimiter = rl.enabled === false\n ? null\n : new RateLimiter(rl.windowMs!, rl.maxRequests!)\n const authLimiter = new RateLimiter(15 * 60_000, 10)\n\n const multiTenantEnabled = config.multiTenant?.enabled === true\n const resolveTenantId = multiTenantEnabled\n ? (req: Request) => resolveTenant(req, storage, 'default')\n : async (_req: Request) => 'default'\n\n const basePath = config.basePath!\n const apiBase = `${basePath}/api/v1`\n const adminBase = `${basePath}/admin`\n const docsPath = `${basePath}/api`\n\n const dashboardEnabled = !!config.dashboard\n const dashboardDir = join(DIST_DIR, 'dashboard')\n\n const swaggerHtml = `<!DOCTYPE html><html><head><title>Consenti API Docs</title>\n<link rel=\"stylesheet\" href=\"https://unpkg.com/swagger-ui-dist@5.17.14/swagger-ui.css\" crossorigin=\"anonymous\"></head>\n<body><div id=\"swagger-ui\"></div>\n<script src=\"https://unpkg.com/swagger-ui-dist@5.17.14/swagger-ui-bundle.js\" crossorigin=\"anonymous\"></script>\n<script src=\"https://unpkg.com/swagger-ui-dist@5.17.14/swagger-ui-standalone-preset.js\" crossorigin=\"anonymous\"></script>\n<script>SwaggerUIBundle({urls:[{url:'${docsPath}/openapi.json',name:'Public API (/consenti/api)'},{url:'${docsPath}/openapi-admin.json',name:'Admin API (/consenti/admin)'}],'urls.primaryName':'Public API (/consenti/api)',dom_id:'#swagger-ui',presets:[SwaggerUIBundle.presets.apis,SwaggerUIStandalonePreset],layout:'StandaloneLayout'})</script>\n</body></html>`\n\n const robotsTxt = `User-agent: *\\nDisallow: ${basePath}/\\n`\n\n const fetchRouter = buildFetchRouter(\n basePath,\n [\n {\n prefix: docsPath,\n rateLimit: false,\n routes: {\n 'GET /docs': async () => new Response(swaggerHtml, { headers: { 'Content-Type': 'text/html; charset=utf-8' } }),\n 'GET /openapi.json': async () => new Response(JSON.stringify(OPENAPI_PUBLIC_SPEC, null, 2), { headers: { 'Content-Type': 'application/json' } }),\n 'GET /openapi-admin.json': async () => new Response(JSON.stringify(OPENAPI_ADMIN_SPEC, null, 2), { headers: { 'Content-Type': 'application/json' } }),\n },\n },\n {\n prefix: '',\n rateLimit: false,\n routes: {\n 'GET /robots.txt': async () => new Response(robotsTxt, { headers: { 'Content-Type': 'text/plain; charset=utf-8' } }),\n },\n },\n {\n prefix: apiBase,\n rateLimit: true,\n routes: {\n ...buildProfileRoutes(profileService),\n ...buildConsentRoutes(consentService, visitorService, profileService, resolveTenantId),\n },\n },\n {\n prefix: adminBase,\n rateLimit: false,\n routes: {\n 'GET /widget.js': async () => serveDistFile(join(DIST_DIR, 'widget', 'widget.js'), 'application/javascript; charset=utf-8'),\n 'GET /widget.css': async () => serveDistFile(join(DIST_DIR, 'widget', 'widget.css'), 'text/css; charset=utf-8'),\n ...buildAdminAuthRoutes(localAuth, storage, authConfig, adminSecret, authLimiter),\n ...buildAdminProfileRoutes(profileService, storage, authConfig, adminSecret),\n ...buildAdminConsentRoutes(storage, authConfig, adminSecret),\n ...buildAdminVisitorRoutes(storage, authConfig, adminSecret),\n ...buildAdminUserRoutes(userService, storage, authConfig, adminSecret),\n ...buildAdminRoleRoutes(storage, authConfig, adminSecret),\n ...buildAdminAuditRoutes(storage, authConfig, adminSecret),\n ...buildAdminStatsRoutes(storage, authConfig, adminSecret),\n ...buildAdminExportRoutes(storage, authConfig, adminSecret),\n ...buildAdminApiKeyRoutes(storage, authConfig, adminSecret),\n ...buildAdminTenantRoutes(storage, authConfig, adminSecret),\n ...buildAdminTcfRoutes(storage, authConfig, adminSecret),\n ...buildAdminCookieTemplateRoutes(storage, authConfig, adminSecret),\n ...buildAdminUITemplateRoutes(storage, authConfig, adminSecret),\n },\n },\n ],\n rateLimiter,\n )\n\n let retentionTimer: ReturnType<typeof setInterval> | null = null\n\n storage\n .connect()\n .then(async () => {\n if (authConfig.mode === 'local' && authConfig.adminEmail && authConfig.adminPassword) {\n await localAuth.bootstrap(authConfig.adminEmail, authConfig.adminPassword)\n }\n await pluginEngine.initialize({ storage, config })\n eventBus.emit('ready')\n\n if (config.tcf?.enabled) {\n startGvlRefresh()\n }\n\n if (config.dataRetention?.purgeAfterDays) {\n const days = config.dataRetention.purgeAfterDays\n const purge = () => storage.purgeExpiredConsents(days)\n .then(n => { if (n > 0) console.warn(`[consenti] Purged ${n} consent records older than ${days} days`) })\n .catch((err: unknown) => console.warn('[consenti] Data retention purge failed:', err))\n void purge()\n retentionTimer = setInterval(() => { void purge() }, 24 * 60 * 60_000)\n }\n })\n .catch((err: unknown) => console.warn('[consenti] Storage connection failed:', err))\n\n async function nodeHandler(req: IncomingMessage, res: ServerResponse): Promise<void> {\n try {\n const rawProto = req.headers['x-forwarded-proto']\n const proto = rawProto === 'https' ? 'https' : 'http'\n const host = req.headers['host'] ?? 'localhost'\n const url = new URL(req.url ?? '/', `${proto}://${host}`)\n\n if (dashboardEnabled && url.pathname.startsWith(basePath)) {\n const served = await tryServeDashboard(url.pathname, basePath, dashboardDir, res)\n if (served) return\n }\n\n const request = await nodeRequestToFetch(req, config.maxBodySize, config.trustedProxies)\n const response = await fetchRouter(request)\n\n if (url.pathname === `${basePath}/api/openapi.json`) {\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify(OPENAPI_PUBLIC_SPEC, null, 2))\n return\n }\n\n if (url.pathname === `${basePath}/api/openapi-admin.json`) {\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify(OPENAPI_ADMIN_SPEC, null, 2))\n return\n }\n\n if (url.pathname === `${basePath}/api/docs`) {\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' })\n res.end(swaggerHtml)\n return\n }\n\n if (\n response.status === 404 &&\n dashboardEnabled &&\n url.pathname.startsWith(basePath) &&\n !url.pathname.startsWith(basePath + '/api/') &&\n !url.pathname.startsWith(basePath + '/admin/')\n ) {\n try {\n const html = await readFile(join(dashboardDir, 'index.html'))\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' })\n res.end(html)\n return\n } catch {\n // dashboard not built — fall through\n }\n }\n\n await fetchResponseToNode(response, res)\n } catch (err) {\n if (!res.headersSent) {\n if (err instanceof PayloadTooLargeError) {\n res.writeHead(413, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ error: 'Payload Too Large' }))\n } else {\n res.writeHead(500, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ error: 'Internal Server Error' }))\n }\n }\n }\n }\n\n function router(\n req: IncomingMessage,\n res: ServerResponse,\n next: (err?: unknown) => void,\n ): void {\n nodeHandler(req, res)\n .then(() => { if (!res.writableEnded) next() })\n .catch(next)\n }\n\n function handler(req: IncomingMessage, res: ServerResponse): Promise<void> {\n return nodeHandler(req, res)\n }\n\n const fastifyPlugin = async (\n fastify: {\n all: (\n path: string,\n handler: (req: { raw: IncomingMessage }, reply: { raw: ServerResponse; hijack: () => void }) => Promise<void>,\n ) => void\n },\n _opts: unknown,\n ): Promise<void> => {\n fastify.all('/*', async (request, reply) => {\n await nodeHandler(request.raw, reply.raw)\n reply.hijack()\n })\n }\n Object.defineProperty(fastifyPlugin, Symbol.for('skip-override'), { value: true })\n\n const fetchHandler = async (request: Request): Promise<Response> => {\n if (dashboardEnabled) {\n const url = new URL(request.url)\n const pathname = url.pathname\n if (pathname.startsWith(basePath)) {\n const rel = pathname.slice(basePath.length) || '/'\n if (!rel.startsWith('/api/') && !rel.startsWith('/admin/')) {\n const target = extname(rel) ? join(dashboardDir, rel) : join(dashboardDir, 'index.html')\n if (!target.startsWith(dashboardDir)) {\n return new Response('Forbidden', { status: 403 })\n }\n try {\n const data = await readFile(target)\n const ct = MIME[extname(target).toLowerCase()] ?? 'application/octet-stream'\n return new Response(data, { headers: { 'Content-Type': ct } })\n } catch {\n try {\n const html = await readFile(join(dashboardDir, 'index.html'))\n return new Response(html, { headers: { 'Content-Type': 'text/html; charset=utf-8' } })\n } catch {\n return new Response(\n 'Dashboard not built. Run: npm run build --workspace=apps/api',\n { status: 404, headers: { 'Content-Type': 'text/plain' } },\n )\n }\n }\n }\n }\n }\n return fetchRouter(request)\n }\n\n const honoApp = { fetch: fetchHandler }\n\n const services = {\n profile: profileService,\n consent: consentService,\n visitor: visitorService,\n user: userService,\n }\n\n return {\n router,\n handler,\n fastifyPlugin,\n honoApp,\n services,\n storage: storage as StorageAdapter,\n eventBus,\n destroy: async () => {\n if (retentionTimer) clearInterval(retentionTimer)\n if (config.tcf?.enabled) stopGvlRefresh()\n await pluginEngine.destroy()\n },\n }\n}\n\nexport { SQLiteAdapter } from './storage/sqlite/sqlite.adapter'\nexport { MongoDBAdapter } from './storage/mongodb/mongodb.adapter'\nexport { MySQLAdapter } from './storage/mysql/mysql.adapter'\nexport { PostgreSQLAdapter } from './storage/postgresql/postgresql.adapter'\n\nexport type {\n ConsentiServerConfig,\n StorageAdapter,\n Profile,\n ConsentDbRecord,\n Visitor,\n AdminUser,\n Role,\n Permission,\n AuditLog,\n ConsentVerifyResult,\n SafeAdminUser,\n} from '@consenti/types'\n","// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","import type {\n ConsentiServerPlugin,\n CreateConsentInput,\n UpdateConsentInput,\n ConsentDbRecord,\n Profile,\n CreateUserInput,\n AdminUser,\n PluginContext,\n} from '@consenti/types'\n\nexport class PluginEngine {\n private plugins: ConsentiServerPlugin[] = []\n\n register(plugins: ConsentiServerPlugin[]): void {\n this.plugins = plugins\n }\n\n async initialize(context: PluginContext): Promise<void> {\n for (const plugin of this.plugins) {\n try { await plugin.initialize?.(context) }\n catch (err) { console.warn(`[Consenti] Plugin \"${plugin.name}\" initialize failed:`, err) }\n }\n }\n\n async destroy(): Promise<void> {\n for (const plugin of this.plugins) {\n try { await plugin.destroy?.() }\n catch (err) { console.warn(`[Consenti] Plugin \"${plugin.name}\" destroy failed:`, err) }\n }\n }\n\n async runBeforeConsentSave(data: CreateConsentInput): Promise<CreateConsentInput> {\n let result = data\n for (const plugin of this.plugins) {\n if (!plugin.beforeConsentSave) continue\n try { result = await plugin.beforeConsentSave(result) }\n catch (err) { console.warn(`[Consenti] Plugin \"${plugin.name}\" beforeConsentSave failed:`, err) }\n }\n return result\n }\n\n async runAfterConsentSave(record: ConsentDbRecord): Promise<void> {\n for (const plugin of this.plugins) {\n if (!plugin.afterConsentSave) continue\n try { await plugin.afterConsentSave(record) }\n catch (err) { console.warn(`[Consenti] Plugin \"${plugin.name}\" afterConsentSave failed:`, err) }\n }\n }\n\n async runBeforeConsentUpdate(data: UpdateConsentInput): Promise<UpdateConsentInput> {\n let result = data\n for (const plugin of this.plugins) {\n if (!plugin.beforeConsentUpdate) continue\n try { result = await plugin.beforeConsentUpdate(result) }\n catch (err) { console.warn(`[Consenti] Plugin \"${plugin.name}\" beforeConsentUpdate failed:`, err) }\n }\n return result\n }\n\n async runAfterConsentUpdate(record: ConsentDbRecord): Promise<void> {\n for (const plugin of this.plugins) {\n if (!plugin.afterConsentUpdate) continue\n try { await plugin.afterConsentUpdate(record) }\n catch (err) { console.warn(`[Consenti] Plugin \"${plugin.name}\" afterConsentUpdate failed:`, err) }\n }\n }\n\n async runAfterProfileFetch(profile: Profile): Promise<Profile> {\n let result = profile\n for (const plugin of this.plugins) {\n if (!plugin.afterProfileFetch) continue\n try { result = await plugin.afterProfileFetch(result) }\n catch (err) { console.warn(`[Consenti] Plugin \"${plugin.name}\" afterProfileFetch failed:`, err) }\n }\n return result\n }\n\n async runBeforeUserCreate(data: CreateUserInput): Promise<CreateUserInput> {\n let result = data\n for (const plugin of this.plugins) {\n if (!plugin.beforeUserCreate) continue\n try { result = await plugin.beforeUserCreate(result) }\n catch (err) { console.warn(`[Consenti] Plugin \"${plugin.name}\" beforeUserCreate failed:`, err) }\n }\n return result\n }\n\n async runAfterUserCreate(user: AdminUser): Promise<void> {\n for (const plugin of this.plugins) {\n if (!plugin.afterUserCreate) continue\n try { await plugin.afterUserCreate(user) }\n catch (err) { console.warn(`[Consenti] Plugin \"${plugin.name}\" afterUserCreate failed:`, err) }\n }\n }\n}\n","const GVL_URL = 'https://vendor-list.consensu.org/v3/vendor-list.json'\nconst REFRESH_MS = 7 * 24 * 60 * 60 * 1000\n\nexport interface GvlPurpose {\n id: number\n name: string\n description: string\n}\n\nexport interface GvlVendor {\n id: number\n name: string\n purposes?: number[]\n legIntPurposes?: number[]\n flexiblePurposes?: number[]\n specialPurposes?: number[]\n features?: number[]\n specialFeatures?: number[]\n}\n\nexport interface GvlData {\n gvlSpecificationVersion: number\n vendorListVersion: number\n vendors: Record<string, GvlVendor>\n purposes: Record<string, GvlPurpose>\n}\n\nlet cachedGvl: GvlData | null = null\nlet lastFetched = 0\nlet refreshTimer: ReturnType<typeof setInterval> | null = null\n\nfunction isGvlData(d: unknown): d is GvlData {\n return typeof d === 'object' && d !== null &&\n 'vendors' in d && 'purposes' in d &&\n typeof (d as GvlData).vendors === 'object' &&\n typeof (d as GvlData).purposes === 'object'\n}\n\nexport async function getGvl(): Promise<GvlData | null> {\n if (cachedGvl && Date.now() - lastFetched < REFRESH_MS) return cachedGvl\n try {\n const res = await fetch(GVL_URL, { signal: AbortSignal.timeout(15_000) })\n if (!res.ok) return cachedGvl\n const data = await res.json()\n if (!isGvlData(data)) return cachedGvl\n cachedGvl = data\n lastFetched = Date.now()\n return cachedGvl\n } catch {\n return cachedGvl\n }\n}\n\nexport function startGvlRefresh(): void {\n if (refreshTimer) return\n void getGvl()\n refreshTimer = setInterval(() => { void getGvl() }, REFRESH_MS)\n}\n\nexport function stopGvlRefresh(): void {\n if (!refreshTimer) return\n clearInterval(refreshTimer)\n refreshTimer = null\n}\n","const SHARED_SCHEMAS = {\n ConsentRecord: {\n type: 'object',\n properties: {\n id: { type: 'string' },\n visitorId: { type: 'string' },\n profileId: { type: 'string' },\n profileVersion: { type: 'integer' },\n locale: { type: 'string' },\n consentJson: { type: 'object', additionalProperties: { type: 'string', enum: ['granted', 'denied', 'objected'] } },\n gpcDetected: { type: 'boolean' },\n source: { type: 'string', enum: ['banner', 'api', 'import'] },\n ageVerified: { type: 'boolean' },\n tcfString: { type: 'string' },\n createdAt: { type: 'string', format: 'date-time' },\n updatedAt: { type: 'string', format: 'date-time' },\n },\n },\n CreateConsentInput: {\n type: 'object',\n required: ['visitorId', 'profileId', 'consentJson'],\n properties: {\n visitorId: { type: 'string' },\n profileId: { type: 'string' },\n consentJson: { type: 'object', additionalProperties: { type: 'string' } },\n gpcDetected: { type: 'boolean', default: false },\n source: { type: 'string', enum: ['banner', 'api', 'import'], default: 'banner' },\n ageVerified: { type: 'boolean' },\n parentalConsentToken: { type: 'string' },\n tcfString: { type: 'string' },\n },\n },\n}\n\nexport const OPENAPI_PUBLIC_SPEC = {\n openapi: '3.1.0',\n info: {\n title: 'Consenti Public API',\n version: '0.1.0',\n description: 'Visitor-facing endpoints for reading consent profiles and submitting/verifying consent. Rate-limited; no authentication required.',\n license: { name: 'Apache 2.0', url: 'https://www.apache.org/licenses/LICENSE-2.0' },\n },\n servers: [\n { url: '/consenti/api', description: 'Consenti Public API' },\n ],\n paths: {\n '/v1/profiles/{id}': {\n get: {\n tags: ['Profile'],\n summary: 'Get profile in its default locale',\n description: 'Returns the resolved profile with banner and modal content for the profile\\'s default locale. Includes `currentLocale`, `locales`, `cookies`, `mainBanner`, `preferenceModal`, and optionally `gpcBanner`.',\n parameters: [\n { name: 'id', in: 'path', required: true, schema: { type: 'string' } },\n ],\n responses: {\n '200': { description: 'Resolved profile for the default locale' },\n '404': { description: 'Profile not found' },\n },\n },\n },\n '/v1/profiles/{id}/{locale}': {\n get: {\n tags: ['Profile'],\n summary: 'Get profile resolved for a specific locale',\n description: 'Same response shape as `GET /v1/profiles/{id}` but resolved for the requested locale, falling back to the default locale for any missing translations.',\n parameters: [\n { name: 'id', in: 'path', required: true, schema: { type: 'string' } },\n { name: 'locale', in: 'path', required: true, schema: { type: 'string', example: 'fr' } },\n ],\n responses: {\n '200': { description: 'Resolved profile for the requested locale' },\n '404': { description: 'Profile not found' },\n },\n },\n },\n '/v1/consent': {\n post: {\n tags: ['Consent'],\n summary: 'Submit consent',\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: { $ref: '#/components/schemas/CreateConsentInput' },\n },\n },\n },\n responses: {\n '200': { description: 'Consent created or updated', content: { 'application/json': { schema: { $ref: '#/components/schemas/ConsentRecord' } } } },\n '400': { description: 'Validation error' },\n },\n },\n },\n '/v1/consent/{visitorId}': {\n get: {\n tags: ['Consent'],\n summary: 'Get consent for visitor',\n parameters: [{ name: 'visitorId', in: 'path', required: true, schema: { type: 'string' } }],\n responses: {\n '200': { description: 'Consent record', content: { 'application/json': { schema: { $ref: '#/components/schemas/ConsentRecord' } } } },\n '404': { description: 'Not found' },\n },\n },\n put: {\n tags: ['Consent'],\n summary: 'Update consent',\n parameters: [{ name: 'visitorId', in: 'path', required: true, schema: { type: 'string' } }],\n responses: { '200': { description: 'Updated consent' } },\n },\n delete: {\n tags: ['Consent'],\n summary: 'GDPR erasure — delete all consent data for visitor',\n parameters: [{ name: 'visitorId', in: 'path', required: true, schema: { type: 'string' } }],\n responses: { '200': { description: 'Erased successfully' } },\n },\n },\n '/v1/consent/{visitorId}/verify': {\n get: {\n tags: ['Consent'],\n summary: 'Verify consent validity',\n parameters: [{ name: 'visitorId', in: 'path', required: true, schema: { type: 'string' } }],\n responses: { '200': { description: 'Verification result' } },\n },\n },\n },\n components: {\n schemas: SHARED_SCHEMAS,\n },\n}\n\nexport const OPENAPI_ADMIN_SPEC = {\n openapi: '3.1.0',\n info: {\n title: 'Consenti Admin API',\n version: '0.1.0',\n description: 'Authenticated endpoints for managing profiles, consent records, users, analytics, and exports. All routes (except `/auth/login`) require `Authorization: Bearer <JWT>`. Obtain a token via `POST /auth/login`.',\n license: { name: 'Apache 2.0', url: 'https://www.apache.org/licenses/LICENSE-2.0' },\n },\n servers: [\n { url: '/consenti/admin', description: 'Consenti Admin API' },\n ],\n paths: {\n // ── Auth ──────────────────────────────────────────────────────────────\n '/auth/login': {\n post: {\n tags: ['Auth'],\n summary: 'Login with email + password',\n requestBody: { required: true, content: { 'application/json': { schema: { type: 'object', properties: { email: { type: 'string' }, password: { type: 'string' } } } } } },\n responses: { '200': { description: 'JWT token' } },\n },\n },\n '/auth/me': {\n get: {\n tags: ['Auth'],\n summary: 'Get current user',\n security: [{ BearerAuth: [] }],\n responses: { '200': { description: 'Current admin user info' } },\n },\n },\n '/auth/logout': {\n post: {\n tags: ['Auth'],\n summary: 'Invalidate session',\n security: [{ BearerAuth: [] }],\n responses: { '200': { description: 'Logged out' } },\n },\n },\n '/auth/oidc/authorize': {\n get: {\n tags: ['Auth'],\n summary: 'Start OIDC authorization (PKCE)',\n responses: { '302': { description: 'Redirect to OIDC provider' } },\n },\n },\n '/auth/oidc/callback': {\n get: {\n tags: ['Auth'],\n summary: 'OIDC callback — exchange code for token',\n responses: { '200': { description: 'JWT token' } },\n },\n },\n '/auth/saml/metadata': {\n get: {\n tags: ['Auth'],\n summary: 'SAML SP metadata XML',\n responses: { '200': { description: 'SAML metadata XML', content: { 'application/xml': {} } } },\n },\n },\n '/auth/saml/acs': {\n post: {\n tags: ['Auth'],\n summary: 'SAML Assertion Consumer Service',\n responses: { '200': { description: 'JWT token' } },\n },\n },\n '/auth/totp/setup': {\n post: {\n tags: ['Auth'],\n summary: 'Setup TOTP MFA',\n security: [{ BearerAuth: [] }],\n responses: { '200': { description: 'TOTP secret and QR URL' } },\n },\n },\n '/auth/totp/verify': {\n post: {\n tags: ['Auth'],\n summary: 'Verify and enable TOTP',\n security: [{ BearerAuth: [] }],\n responses: { '200': { description: 'TOTP enabled' } },\n },\n },\n // ── Profiles ──────────────────────────────────────────────────────────\n '/profiles': {\n get: {\n tags: ['Profiles'],\n summary: 'List profiles',\n security: [{ BearerAuth: [] }],\n responses: { '200': { description: 'Array of profiles' } },\n },\n post: {\n tags: ['Profiles'],\n summary: 'Create profile',\n security: [{ BearerAuth: [] }],\n responses: { '201': { description: 'Created profile' } },\n },\n },\n // ── Consents ──────────────────────────────────────────────────────────\n '/consents': {\n get: {\n tags: ['Consents'],\n summary: 'List consent records',\n security: [{ BearerAuth: [] }],\n parameters: [\n { name: 'page', in: 'query', schema: { type: 'integer' } },\n { name: 'profileId', in: 'query', schema: { type: 'string' } },\n { name: 'from', in: 'query', schema: { type: 'string', format: 'date' } },\n { name: 'to', in: 'query', schema: { type: 'string', format: 'date' } },\n ],\n responses: { '200': { description: 'Paginated consent records' } },\n },\n },\n // ── Stats ─────────────────────────────────────────────────────────────\n '/stats/overview': {\n get: {\n tags: ['Stats'],\n summary: 'Overview statistics',\n security: [{ BearerAuth: [] }],\n responses: { '200': { description: 'Totals and acceptance rates' } },\n },\n },\n '/stats/timeline': {\n get: {\n tags: ['Stats'],\n summary: 'Daily consent timeline',\n security: [{ BearerAuth: [] }],\n parameters: [{ name: 'days', in: 'query', schema: { type: 'integer', default: 30 } }],\n responses: { '200': { description: 'Array of date+count' } },\n },\n },\n '/stats/countries': {\n get: {\n tags: ['Stats'],\n summary: 'Consent by country',\n security: [{ BearerAuth: [] }],\n responses: { '200': { description: 'Country counts' } },\n },\n },\n '/stats/gpc': {\n get: {\n tags: ['Stats'],\n summary: 'GPC detection stats',\n security: [{ BearerAuth: [] }],\n responses: { '200': { description: 'GPC rate and counts' } },\n },\n },\n // ── Export ────────────────────────────────────────────────────────────\n '/export/consents': {\n get: {\n tags: ['Export'],\n summary: 'Export consent records',\n security: [{ BearerAuth: [] }],\n parameters: [\n { name: 'format', in: 'query', schema: { type: 'string', enum: ['csv', 'json'] } },\n { name: 'from', in: 'query', schema: { type: 'string', format: 'date' } },\n { name: 'to', in: 'query', schema: { type: 'string', format: 'date' } },\n ],\n responses: { '200': { description: 'CSV or JSON download' } },\n },\n },\n // ── Tenants ───────────────────────────────────────────────────────────\n '/tenants': {\n get: {\n tags: ['Sites'],\n summary: 'List all sites/tenants',\n security: [{ BearerAuth: [] }],\n responses: { '200': { description: 'Array of tenants' } },\n },\n post: {\n tags: ['Sites'],\n summary: 'Create a site/tenant',\n security: [{ BearerAuth: [] }],\n requestBody: { required: true, content: { 'application/json': { schema: { type: 'object', properties: { name: { type: 'string' }, slug: { type: 'string' } }, required: ['name', 'slug'] } } } },\n responses: { '201': { description: 'Created tenant' } },\n },\n },\n '/tenants/{id}': {\n put: {\n tags: ['Sites'],\n summary: 'Update a site/tenant',\n security: [{ BearerAuth: [] }],\n parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'string' } }],\n responses: { '200': { description: 'Updated tenant' } },\n },\n delete: {\n tags: ['Sites'],\n summary: 'Delete a site/tenant',\n security: [{ BearerAuth: [] }],\n parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'string' } }],\n responses: { '200': { description: 'Deleted' } },\n },\n },\n },\n components: {\n securitySchemes: {\n BearerAuth: { type: 'http', scheme: 'bearer', bearerFormat: 'JWT' },\n },\n schemas: SHARED_SCHEMAS,\n },\n}\n","import { createHash, createHmac, randomUUID, scryptSync, randomBytes, timingSafeEqual } from 'node:crypto'\n\nexport { randomUUID }\n\nexport function randomProfileId(): string {\n return `prof_${randomBytes(20).toString('hex')}`\n}\n\nexport function hashIp(ip: string): string {\n return createHash('sha256').update(ip).digest('hex')\n}\n\nexport function hashUserAgent(ua: string): string {\n return createHash('sha256').update(ua).digest('hex')\n}\n\nexport function signHmac(payload: string, secret: string): string {\n return createHmac('sha256', secret).update(payload).digest('hex')\n}\n\nexport function verifyHmac(payload: string, signature: string, secret: string): boolean {\n const expected = Buffer.from(signHmac(payload, secret), 'hex')\n const actual = Buffer.from(signature, 'hex')\n if (expected.length !== actual.length) return false\n return timingSafeEqual(expected, actual)\n}\n\nexport function hashPassword(password: string): string {\n const salt = randomBytes(16).toString('hex')\n const hash = scryptSync(password, salt, 64).toString('hex')\n return `${salt}:${hash}`\n}\n\nexport function verifyPassword(password: string, stored: string): boolean {\n const [salt, hash] = stored.split(':')\n if (!salt || !hash) return false\n const derived = scryptSync(password, salt, 64).toString('hex')\n return timingSafeEqual(Buffer.from(hash, 'hex'), Buffer.from(derived, 'hex'))\n}\n\nexport function signJwt(payload: Record<string, unknown>, secret: string, expiresInSeconds = 3600): string {\n const now = Math.floor(Date.now() / 1000)\n const header = btoa(JSON.stringify({ alg: 'HS256', typ: 'JWT' })).replace(/=/g, '')\n const body = btoa(JSON.stringify({ ...payload, iat: now, exp: now + expiresInSeconds })).replace(/=/g, '')\n const sig = signHmac(`${header}.${body}`, secret)\n .match(/.{2}/g)!\n .map(h => String.fromCharCode(parseInt(h, 16)))\n .join('')\n const sigEncoded = btoa(sig).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '')\n return `${header}.${body}.${sigEncoded}`\n}\n\nexport function verifyJwt(token: string, secret: string): Record<string, unknown> | null {\n const parts = token.split('.')\n if (parts.length !== 3) return null\n const [header, body, sigEncoded] = parts\n if (!header || !body || !sigEncoded) return null\n const expected = signHmac(`${header}.${body}`, secret)\n const sigBytes = atob(sigEncoded.replace(/-/g, '+').replace(/_/g, '/'))\n const actualHex = Array.from(sigBytes).map(c => c.charCodeAt(0).toString(16).padStart(2, '0')).join('')\n const expectedBuf = Buffer.from(expected, 'hex')\n const actualBuf = Buffer.from(actualHex, 'hex')\n if (expectedBuf.length !== actualBuf.length || !timingSafeEqual(expectedBuf, actualBuf)) return null\n try {\n const payload = JSON.parse(atob(body)) as Record<string, unknown>\n const exp = payload['exp']\n if (typeof exp === 'number' && Date.now() / 1000 > exp) return null\n return payload\n } catch {\n return null\n }\n}\n","// Single source of truth for schema definitions, seed data, and SQL generation.\n// Document DBs (JSON, MongoDB) use the JS objects directly.\n// SQL DBs (SQLite, PostgreSQL, MySQL) import the generated SQL exports.\n\n// ── Schema definition types ───────────────────────────────────────────────────\n\n/** Abstract column types — each SQL dialect maps these to its native type. */\nexport type ColType =\n | 'pk' // String primary key\n | 'text' // Short-medium text (TEXT in SQLite/PG; VARCHAR(255) in MySQL)\n | 'text_sm' // Short code ≤20 (TEXT in SQLite/PG; VARCHAR(20) in MySQL)\n | 'text_md' // Medium text ≤100 (TEXT in SQLite/PG; VARCHAR(100) in MySQL)\n | 'text_geo' // Geo code ≤10 (TEXT in SQLite/PG; VARCHAR(10) in MySQL)\n | 'text_hash' // Hash string ≤64 (TEXT in SQLite/PG; VARCHAR(64) in MySQL)\n | 'longtext' // Long text (TEXT in SQLite/PG; LONGTEXT in MySQL)\n | 'json' // JSON blob (TEXT in SQLite; JSONB in PG; LONGTEXT in MySQL)\n | 'int' // Integer\n | 'bool' // Boolean (INTEGER 0/1 in SQLite; BOOLEAN in PG; TINYINT(1) in MySQL)\n | 'ts' // Timestamp with current-time default\n\nexport interface ColDef {\n n: string // column name\n t: ColType\n null?: true // nullable; omit = NOT NULL\n def?: string | number | boolean // '$now'→now(), '$arr'→'[]', '$obj'→'{}'\n unique?: true\n ref?: string // REFERENCES <ref>(id)\n onDel?: 'CASCADE'\n mysqlUpd?: true // MySQL: ON UPDATE CURRENT_TIMESTAMP\n}\n\nexport interface TableDef {\n name: string\n cols: ColDef[]\n pk?: string[] // composite primary key\n uq?: { cols: string[] }[] // composite unique constraints\n}\n\n// ── Table definitions ─────────────────────────────────────────────────────────\n\nconst tenants: TableDef = {\n name: 'tenants',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'name', t: 'text' },\n { n: 'slug', t: 'text', unique: true },\n { n: 'created_at', t: 'ts', def: '$now' },\n { n: 'updated_at', t: 'ts', def: '$now', mysqlUpd: true },\n ],\n}\n\nconst profiles: TableDef = {\n name: 'profiles',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants' },\n { n: 'name', t: 'text' },\n { n: 'default_locale', t: 'text_sm', def: 'en' },\n { n: 'version', t: 'int', def: 1 },\n { n: 'profile_json', t: 'json' },\n { n: 'created_at', t: 'ts', def: '$now' },\n { n: 'updated_at', t: 'ts', def: '$now', mysqlUpd: true },\n ],\n}\n\n// SQLite initial schema — without enterprise columns (added via ALTER TABLE in v3 migration)\nconst consentRecordsBase: TableDef = {\n name: 'consent_records',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants' },\n { n: 'visitor_id', t: 'text' },\n { n: 'profile_id', t: 'text', ref: 'profiles' },\n { n: 'profile_version', t: 'int' },\n { n: 'locale', t: 'text_sm' },\n { n: 'consent_json', t: 'json' },\n { n: 'gpc_detected', t: 'bool', def: false },\n { n: 'source', t: 'text_sm' },\n { n: 'created_at', t: 'ts', def: '$now' },\n { n: 'updated_at', t: 'ts', def: '$now', mysqlUpd: true },\n ],\n uq: [{ cols: ['visitor_id', 'profile_id'] }],\n}\n\n// Full schema — includes enterprise columns; used for PostgreSQL/MySQL\nconst consentRecordsFull: TableDef = {\n name: 'consent_records',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants' },\n { n: 'visitor_id', t: 'text' },\n { n: 'profile_id', t: 'text', ref: 'profiles' },\n { n: 'profile_version', t: 'int' },\n { n: 'locale', t: 'text_sm' },\n { n: 'consent_json', t: 'json' },\n { n: 'gpc_detected', t: 'bool', def: false },\n { n: 'source', t: 'text_sm' },\n { n: 'age_verified', t: 'bool', def: false },\n { n: 'parental_consent_token', t: 'longtext', null: true },\n { n: 'tcf_string', t: 'longtext', null: true },\n { n: 'created_at', t: 'ts', def: '$now' },\n { n: 'updated_at', t: 'ts', def: '$now', mysqlUpd: true },\n ],\n uq: [{ cols: ['visitor_id', 'profile_id'] }],\n}\n\nconst consentHistory: TableDef = {\n name: 'consent_history',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants' },\n { n: 'consent_record_id', t: 'text', ref: 'consent_records' },\n { n: 'visitor_id', t: 'text' },\n { n: 'old_json', t: 'json', null: true },\n { n: 'new_json', t: 'json' },\n { n: 'action', t: 'text_sm' },\n { n: 'created_at', t: 'ts', def: '$now' },\n ],\n}\n\nconst visitors: TableDef = {\n name: 'visitors',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants' },\n { n: 'visitor_id', t: 'text', unique: true },\n { n: 'country', t: 'text_geo', null: true },\n { n: 'region', t: 'text_md', null: true },\n { n: 'city', t: 'text_md', null: true },\n { n: 'ip_hash', t: 'text_hash', null: true },\n { n: 'user_agent_hash', t: 'text_hash', null: true },\n { n: 'first_seen', t: 'ts', def: '$now' },\n { n: 'last_seen', t: 'ts', def: '$now', mysqlUpd: true },\n ],\n}\n\n// SQLite initial schema — without TOTP columns (added via ALTER TABLE in v3 migration)\nconst usersBase: TableDef = {\n name: 'users',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants' },\n { n: 'name', t: 'text' },\n { n: 'email', t: 'text', unique: true },\n { n: 'password_hash', t: 'text' },\n { n: 'is_active', t: 'bool', def: true },\n { n: 'created_at', t: 'ts', def: '$now' },\n { n: 'updated_at', t: 'ts', def: '$now', mysqlUpd: true },\n ],\n}\n\n// Full schema — includes TOTP columns; used for PostgreSQL/MySQL\nconst usersFull: TableDef = {\n name: 'users',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants' },\n { n: 'name', t: 'text' },\n { n: 'email', t: 'text', unique: true },\n { n: 'password_hash', t: 'text' },\n { n: 'is_active', t: 'bool', def: true },\n { n: 'totp_secret', t: 'longtext', null: true },\n { n: 'totp_enabled', t: 'bool', def: false },\n { n: 'created_at', t: 'ts', def: '$now' },\n { n: 'updated_at', t: 'ts', def: '$now', mysqlUpd: true },\n ],\n}\n\nconst roles: TableDef = {\n name: 'roles',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants' },\n { n: 'name', t: 'text_md' },\n { n: 'description', t: 'text', null: true },\n ],\n}\n\nconst permissions: TableDef = {\n name: 'permissions',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'name', t: 'text_md', unique: true },\n { n: 'description', t: 'text', null: true },\n ],\n}\n\n// SQLite v1 — no tenant_id column (added via ALTER TABLE in v4 migration)\nconst userRolesBase: TableDef = {\n name: 'user_roles',\n cols: [\n { n: 'user_id', t: 'text', ref: 'users' },\n { n: 'role_id', t: 'text', ref: 'roles' },\n ],\n pk: ['user_id', 'role_id'],\n}\n\n// Full schema with tenant_id — used for PostgreSQL/MySQL\nconst userRolesFull: TableDef = {\n name: 'user_roles',\n cols: [\n { n: 'user_id', t: 'text', ref: 'users' },\n { n: 'role_id', t: 'text', ref: 'roles' },\n { n: 'tenant_id', t: 'text', def: 'default' },\n ],\n pk: ['user_id', 'role_id', 'tenant_id'],\n}\n\nconst rolePermissions: TableDef = {\n name: 'role_permissions',\n cols: [\n { n: 'role_id', t: 'text', ref: 'roles' },\n { n: 'permission_id', t: 'text', ref: 'permissions' },\n ],\n pk: ['role_id', 'permission_id'],\n}\n\nconst auditLogs: TableDef = {\n name: 'audit_logs',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants' },\n { n: 'user_id', t: 'text', null: true },\n { n: 'action', t: 'text_md' },\n { n: 'resource_type', t: 'text_md' },\n { n: 'resource_id', t: 'text', null: true },\n { n: 'old_data', t: 'json', null: true },\n { n: 'new_data', t: 'json', null: true },\n { n: 'created_at', t: 'ts', def: '$now' },\n ],\n}\n\nconst apiKeys: TableDef = {\n name: 'api_keys',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants', onDel: 'CASCADE' },\n { n: 'key_hash', t: 'text_hash', unique: true },\n { n: 'name', t: 'text' },\n { n: 'is_active', t: 'bool', def: true },\n { n: 'created_at', t: 'ts', def: '$now' },\n ],\n}\n\nconst cookieTemplates: TableDef = {\n name: 'cookie_templates',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants', onDel: 'CASCADE' },\n { n: 'name', t: 'text' },\n { n: 'cookies_json', t: 'json', def: '$arr' },\n { n: 'created_at', t: 'ts', def: '$now' },\n { n: 'updated_at', t: 'ts', def: '$now', mysqlUpd: true },\n ],\n}\n\nconst uiTemplates: TableDef = {\n name: 'ui_templates',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants', onDel: 'CASCADE' },\n { n: 'name', t: 'text' },\n { n: 'settings_json', t: 'json', def: '$obj' },\n { n: 'created_at', t: 'ts', def: '$now' },\n { n: 'updated_at', t: 'ts', def: '$now', mysqlUpd: true },\n ],\n}\n\n// ── Exported table definition groups ─────────────────────────────────────────\n\n/** Core tables for SQLite initial (v1) migration — no enterprise columns, no tenant_id in user_roles. */\nexport const CORE_TABLES_SQLITE: readonly TableDef[] = [\n tenants, profiles, consentRecordsBase, consentHistory, visitors,\n usersBase, roles, permissions, userRolesBase, rolePermissions, auditLogs,\n]\n\n/** Core tables with all current columns — for PostgreSQL/MySQL full initial schema. */\nexport const CORE_TABLES_FULL: readonly TableDef[] = [\n tenants, profiles, consentRecordsFull, consentHistory, visitors,\n usersFull, roles, permissions, userRolesFull, rolePermissions, auditLogs,\n]\n\n/** api_keys table — SQLite v2 migration. */\nexport const API_KEY_TABLES: readonly TableDef[] = [apiKeys]\n\n/** Template tables — SQLite v5 migration. */\nexport const TEMPLATE_TABLES: readonly TableDef[] = [cookieTemplates, uiTemplates]\n\n// ── SQL generators ────────────────────────────────────────────────────────────\n\nfunction sqliteDef(def: string | number | boolean): string {\n if (def === '$now') return `DEFAULT (datetime('now'))`\n if (def === '$arr') return `DEFAULT '[]'`\n if (def === '$obj') return `DEFAULT '{}'`\n if (def === true) return 'DEFAULT 1'\n if (def === false) return 'DEFAULT 0'\n if (typeof def === 'string') return `DEFAULT '${def}'`\n return `DEFAULT ${def}`\n}\n\nfunction buildColSQLite(c: ColDef): string {\n if (c.t === 'pk') return `${c.n} TEXT PRIMARY KEY`\n const type = (c.t === 'int' || c.t === 'bool') ? 'INTEGER' : 'TEXT'\n const parts = [`${c.n} ${type}`]\n if (!c.null) parts.push('NOT NULL')\n if (c.def !== undefined) parts.push(sqliteDef(c.def))\n if (c.unique) parts.push('UNIQUE')\n if (c.ref) { parts.push(`REFERENCES ${c.ref}(id)`); if (c.onDel) parts.push(`ON DELETE ${c.onDel}`) }\n return parts.join(' ')\n}\n\nfunction buildTableSQLite(t: TableDef): string {\n const lines = t.cols.map(c => ` ${buildColSQLite(c)}`)\n if (t.pk) lines.push(` PRIMARY KEY (${t.pk.join(', ')})`)\n if (t.uq) for (const u of t.uq) lines.push(` UNIQUE(${u.cols.join(', ')})`)\n return `CREATE TABLE IF NOT EXISTS ${t.name} (\\n${lines.join(',\\n')}\\n);`\n}\n\nfunction pgDef(def: string | number | boolean): string {\n if (def === '$now') return 'DEFAULT NOW()'\n if (def === '$arr') return `DEFAULT '[]'`\n if (def === '$obj') return `DEFAULT '{}'`\n if (def === true) return 'DEFAULT TRUE'\n if (def === false) return 'DEFAULT FALSE'\n if (typeof def === 'string') return `DEFAULT '${def}'`\n return `DEFAULT ${def}`\n}\n\nfunction buildColPg(c: ColDef): string {\n if (c.t === 'pk') return `${c.n} TEXT PRIMARY KEY`\n const type = c.t === 'json' ? 'JSONB' : c.t === 'int' ? 'INTEGER' : c.t === 'bool' ? 'BOOLEAN' : c.t === 'ts' ? 'TIMESTAMPTZ' : 'TEXT'\n const parts = [`${c.n} ${type}`]\n if (!c.null) parts.push('NOT NULL')\n if (c.def !== undefined) parts.push(pgDef(c.def))\n if (c.unique) parts.push('UNIQUE')\n if (c.ref) { parts.push(`REFERENCES ${c.ref}(id)`); if (c.onDel) parts.push(`ON DELETE ${c.onDel}`) }\n return parts.join(' ')\n}\n\nfunction buildTablePg(t: TableDef): string {\n const lines = t.cols.map(c => ` ${buildColPg(c)}`)\n if (t.pk) lines.push(` PRIMARY KEY (${t.pk.join(', ')})`)\n if (t.uq) for (const u of t.uq) lines.push(` UNIQUE (${u.cols.join(', ')})`)\n return `CREATE TABLE IF NOT EXISTS ${t.name} (\\n${lines.join(',\\n')}\\n);`\n}\n\nconst MYSQL_TEXT: Partial<Record<ColType, string>> = {\n text: 'VARCHAR(255)', text_sm: 'VARCHAR(20)', text_md: 'VARCHAR(100)',\n text_geo: 'VARCHAR(10)', text_hash: 'VARCHAR(64)', longtext: 'LONGTEXT', json: 'LONGTEXT',\n}\n\nfunction mysqlDef(def: string | number | boolean): string {\n if (def === '$now') return 'DEFAULT CURRENT_TIMESTAMP'\n if (def === '$arr') return `DEFAULT '[]'`\n if (def === '$obj') return `DEFAULT '{}'`\n if (def === true) return 'DEFAULT 1'\n if (def === false) return 'DEFAULT 0'\n if (typeof def === 'string') return `DEFAULT '${def}'`\n return `DEFAULT ${def}`\n}\n\nfunction buildColMySQL(c: ColDef): string {\n if (c.t === 'pk') return `${c.n} VARCHAR(36) PRIMARY KEY`\n const type = c.t === 'int' ? 'INT' : c.t === 'bool' ? 'TINYINT(1)' : c.t === 'ts' ? 'DATETIME' : (MYSQL_TEXT[c.t] ?? 'TEXT')\n const parts = [`${c.n} ${type}`]\n if (!c.null) parts.push('NOT NULL')\n if (c.def !== undefined) parts.push(mysqlDef(c.def))\n if (c.mysqlUpd) parts.push('ON UPDATE CURRENT_TIMESTAMP')\n if (c.unique) parts.push('UNIQUE')\n if (c.ref) { parts.push(`REFERENCES ${c.ref}(id)`); if (c.onDel) parts.push(`ON DELETE ${c.onDel}`) }\n return parts.join(' ')\n}\n\nfunction buildTableMySQL(t: TableDef): string {\n const lines = t.cols.map(c => ` ${buildColMySQL(c)}`)\n if (t.pk) lines.push(` PRIMARY KEY (${t.pk.join(', ')})`)\n if (t.uq) for (const u of t.uq) lines.push(` UNIQUE KEY uq_${u.cols.join('_')} (${u.cols.join(', ')})`)\n return `CREATE TABLE IF NOT EXISTS ${t.name} (\\n${lines.join(',\\n')}\\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;`\n}\n\nfunction toSQLite(tables: readonly TableDef[]): string { return tables.map(buildTableSQLite).join('\\n') }\nfunction toPostgres(tables: readonly TableDef[]): string { return tables.map(buildTablePg).join('\\n') }\nfunction toMySQL(tables: readonly TableDef[]): string { return tables.map(buildTableMySQL).join('\\n') }\n\n// ── Schema SQL exports ────────────────────────────────────────────────────────\n// SQLite: separate blocks matching its versioned migration steps.\n// PostgreSQL/MySQL: one block containing the full current schema.\n\n/** SQLite v1 migration: core tables. */\nexport const SCHEMA_SQL_SQLITE = toSQLite(CORE_TABLES_SQLITE)\n\n/** SQLite v2 migration: api_keys table. */\nexport const SCHEMA_SQL_SQLITE_API_KEYS = toSQLite(API_KEY_TABLES)\n\n/** SQLite v3 migration: enterprise columns added via ALTER TABLE (not generatable from TableDef). */\nexport const SCHEMA_SQL_SQLITE_ENTERPRISE = `\nALTER TABLE consent_records ADD COLUMN age_verified INTEGER NOT NULL DEFAULT 0;\nALTER TABLE consent_records ADD COLUMN parental_consent_token TEXT;\nALTER TABLE consent_records ADD COLUMN tcf_string TEXT;\nALTER TABLE users ADD COLUMN totp_secret TEXT;\nALTER TABLE users ADD COLUMN totp_enabled INTEGER NOT NULL DEFAULT 0;\n`\n\n/** SQLite v5 migration: template tables. */\nexport const SCHEMA_SQL_SQLITE_TEMPLATES = toSQLite(TEMPLATE_TABLES)\n\nconst ALL_TABLES_FULL: readonly TableDef[] = [...CORE_TABLES_FULL, ...API_KEY_TABLES, ...TEMPLATE_TABLES]\n\n/** PostgreSQL full schema — all tables with current column set. */\nexport const SCHEMA_SQL_POSTGRES =\n toPostgres(ALL_TABLES_FULL) +\n '\\nCREATE TABLE IF NOT EXISTS schema_version (version INTEGER PRIMARY KEY);\\n'\n\n/** MySQL full schema — all tables with current column set. */\nexport const SCHEMA_SQL_MYSQL =\n toMySQL(ALL_TABLES_FULL) +\n '\\nCREATE TABLE IF NOT EXISTS schema_version (\\n version INT NOT NULL PRIMARY KEY\\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\\n'\n\n// ── Core data ─────────────────────────────────────────────────────────────────\n\nexport interface SeedPermission { id: string; name: string; description: string }\nexport interface SeedRole { id: string; tenantId: string; name: string; description: string }\nexport interface SeedRolePermission { roleId: string; permissionId: string }\n\nexport const SEED_TENANT = { id: 'default', name: 'Default', slug: 'default' } as const\n\nexport const SEED_PERMISSIONS: SeedPermission[] = [\n { id: 'perm_profile_create', name: 'profile:create', description: 'Create profiles' },\n { id: 'perm_profile_update', name: 'profile:update', description: 'Update profiles' },\n { id: 'perm_profile_delete', name: 'profile:delete', description: 'Delete profiles' },\n { id: 'perm_profile_view', name: 'profile:view', description: 'View profiles' },\n { id: 'perm_consent_view', name: 'consent:view', description: 'View consent records' },\n { id: 'perm_visitor_view', name: 'visitor:view', description: 'View visitor records' },\n { id: 'perm_user_create', name: 'user:create', description: 'Create users' },\n { id: 'perm_user_update', name: 'user:update', description: 'Update users' },\n { id: 'perm_user_delete', name: 'user:delete', description: 'Delete users' },\n { id: 'perm_user_view', name: 'user:view', description: 'View users' },\n { id: 'perm_role_create', name: 'role:create', description: 'Create roles' },\n { id: 'perm_role_update', name: 'role:update', description: 'Update roles' },\n { id: 'perm_role_delete', name: 'role:delete', description: 'Delete roles' },\n { id: 'perm_role_view', name: 'role:view', description: 'View roles' },\n { id: 'perm_audit_view', name: 'audit:view', description: 'View audit logs' },\n { id: 'perm_settings_update', name: 'settings:update', description: 'Update settings' },\n { id: 'perm_export_run', name: 'export:run', description: 'Run data exports' },\n]\n\nexport const SEED_ROLES: SeedRole[] = [\n { id: 'role_super_admin', tenantId: 'default', name: 'super_admin', description: 'Full system access' },\n { id: 'role_admin', tenantId: 'default', name: 'admin', description: 'Administrative access' },\n { id: 'role_compliance_officer', tenantId: 'default', name: 'compliance_officer', description: 'Compliance read access' },\n { id: 'role_viewer', tenantId: 'default', name: 'viewer', description: 'Read-only access' },\n]\n\nconst adminExcluded = new Set(['role:delete', 'user:delete'])\nconst complianceAllowed = new Set(['consent:view', 'visitor:view', 'audit:view', 'profile:view', 'export:run'])\nconst viewerAllowed = new Set(['consent:view', 'visitor:view', 'profile:view'])\n\nexport const SEED_ROLE_PERMISSIONS: SeedRolePermission[] = [\n ...SEED_PERMISSIONS.map(p => ({ roleId: 'role_super_admin', permissionId: p.id })),\n ...SEED_PERMISSIONS.filter(p => !adminExcluded.has(p.name)).map(p => ({ roleId: 'role_admin', permissionId: p.id })),\n ...SEED_PERMISSIONS.filter(p => complianceAllowed.has(p.name)).map(p => ({ roleId: 'role_compliance_officer', permissionId: p.id })),\n ...SEED_PERMISSIONS.filter(p => viewerAllowed.has(p.name)).map(p => ({ roleId: 'role_viewer', permissionId: p.id })),\n]\n\n// ── SQLite seed SQL ───────────────────────────────────────────────────────────\n// Generated from seed data above — idempotent via INSERT OR IGNORE.\n// MongoDB, MySQL, PostgreSQL adapters use the typed JS objects directly.\n\nfunction q(s: string): string { return `'${s.replace(/'/g, \"''\")}'` }\n\nfunction generateSeedSQL(): string {\n const { id, name, slug } = SEED_TENANT\n const tenant = `INSERT OR IGNORE INTO tenants (id, name, slug) VALUES (${q(id)},${q(name)},${q(slug)});`\n\n const perms = `INSERT OR IGNORE INTO permissions (id, name, description) VALUES\\n${\n SEED_PERMISSIONS.map(p => ` (${q(p.id)},${q(p.name)},${q(p.description)})`).join(',\\n')\n };`\n\n const rolesSQL = `INSERT OR IGNORE INTO roles (id, tenant_id, name, description) VALUES\\n${\n SEED_ROLES.map(r => ` (${q(r.id)},${q(r.tenantId)},${q(r.name)},${q(r.description)})`).join(',\\n')\n };`\n\n const byRole = new Map<string, string[]>()\n for (const rp of SEED_ROLE_PERMISSIONS) {\n if (!byRole.has(rp.roleId)) byRole.set(rp.roleId, [])\n byRole.get(rp.roleId)!.push(rp.permissionId)\n }\n const rolePerms = [...byRole.entries()].map(([roleId, permIds]) =>\n `INSERT OR IGNORE INTO role_permissions (role_id, permission_id) VALUES\\n${\n permIds.map(pid => ` (${q(roleId)},${q(pid)})`).join(',\\n')\n };`\n ).join('\\n')\n\n return [tenant, perms, rolesSQL, rolePerms].join('\\n')\n}\n\nexport const SEED_SQL = generateSeedSQL()\n","import type { Database as DB, Statement } from 'better-sqlite3'\n\nconst MAX_PAGE_SIZE = 500\nimport { randomUUID, randomProfileId } from '../../utils/crypto'\nimport {\n SEED_SQL,\n SCHEMA_SQL_SQLITE,\n SCHEMA_SQL_SQLITE_API_KEYS,\n SCHEMA_SQL_SQLITE_ENTERPRISE,\n SCHEMA_SQL_SQLITE_TEMPLATES,\n} from '../seed-data'\nimport type {\n StorageAdapter,\n StorageConfig,\n Profile,\n ProfileConfig,\n CreateProfileInput,\n UpdateProfileInput,\n ConsentDbRecord,\n ConsentHistoryEntry,\n ConsentValue,\n CreateConsentInput,\n UpdateConsentInput,\n ConsentFilters,\n Visitor,\n VisitorFilters,\n CreateVisitorInput,\n UpdateVisitorInput,\n AdminUser,\n CreateUserInput,\n UpdateUserInput,\n Role,\n CreateRoleInput,\n UpdateRoleInput,\n Permission,\n AuditLog,\n AuditFilters,\n CreateAuditLogInput,\n OverviewStats,\n CategoryStats,\n TimelineEntry,\n CountryStat,\n GpcStats,\n Tenant,\n ApiKey,\n CreateApiKeyInput,\n CreateTenantInput,\n UpdateTenantInput,\n ServerCookieTemplate,\n ServerUITemplate,\n CreateCookieTemplateInput,\n UpdateCookieTemplateInput,\n CreateUITemplateInput,\n UpdateUITemplateInput,\n} from '@consenti/types'\n\ninterface RawProfile {\n id: string; tenant_id: string; name: string; default_locale: string\n version: number; profile_json: string\n created_at: string; updated_at: string\n}\ninterface RawConsent {\n id: string; tenant_id: string; visitor_id: string; profile_id: string\n profile_version: number; locale: string; consent_json: string\n gpc_detected: number; source: string; created_at: string; updated_at: string\n age_verified?: number; parental_consent_token?: string | null; tcf_string?: string | null\n}\ninterface RawConsentHistory {\n id: string; tenant_id: string; consent_record_id: string; visitor_id: string\n old_json: string | null; new_json: string; action: string; created_at: string\n}\ninterface RawVisitor {\n id: string; tenant_id: string; visitor_id: string\n country: string | null; region: string | null; city: string | null\n ip_hash: string | null; user_agent_hash: string | null\n first_seen: string; last_seen: string\n}\ninterface RawUser {\n id: string; tenant_id: string; name: string; email: string\n password_hash: string; is_active: number; created_at: string; updated_at: string\n totp_secret?: string | null; totp_enabled?: number\n}\ninterface RawRole {\n id: string; tenant_id: string; name: string; description: string | null\n}\ninterface RawPermission {\n id: string; name: string; description: string | null\n}\ninterface RawAuditLog {\n id: string; tenant_id: string; user_id: string | null; action: string\n resource_type: string; resource_id: string | null\n old_data: string | null; new_data: string | null; created_at: string\n}\ninterface RawTenant {\n id: string; name: string; slug: string; created_at: string; updated_at: string\n}\ninterface RawApiKey {\n id: string; tenant_id: string; key_hash: string; name: string; is_active: number; created_at: string\n}\n\ninterface RawCookieTemplate {\n id: string; tenant_id: string; name: string; cookies_json: string; created_at: string; updated_at: string\n}\ninterface RawUITemplate {\n id: string; tenant_id: string; name: string; settings_json: string; created_at: string; updated_at: string\n}\n\n\ntype Stmt = Statement\n\nexport class BetterSqlite3Adapter implements StorageAdapter {\n private db!: DB\n private cache = new Map<string, Stmt>()\n\n constructor(private config: StorageConfig) {}\n\n private stmt(sql: string): Stmt {\n let s = this.cache.get(sql)\n if (!s) { s = this.db.prepare(sql); this.cache.set(sql, s) }\n return s\n }\n\n async connect(): Promise<void> {\n // Lazy: only loaded when this driver is selected — keeps better-sqlite3\n // as an optional peer dep without crashing startup for other drivers.\n const mod = await import('better-sqlite3').catch(() => {\n throw new Error(\"driver 'better-sqlite3' requires: npm install better-sqlite3\")\n }) as { default: new(path: string) => DB }\n this.db = new mod.default(this.config.path ?? './consenti.db')\n this.db.exec('PRAGMA journal_mode=WAL')\n this.db.exec('PRAGMA foreign_keys=ON')\n this.db.exec('PRAGMA synchronous=NORMAL')\n await this.migrate()\n }\n\n async disconnect(): Promise<void> {\n this.cache.clear()\n this.db.close()\n }\n\n async migrate(): Promise<void> {\n const row = this.db.prepare('PRAGMA user_version').get() as { user_version: number }\n if (row.user_version < 1) {\n this.db.exec(SCHEMA_SQL_SQLITE)\n this.db.exec(SEED_SQL)\n this.db.exec('PRAGMA user_version = 1')\n }\n if (row.user_version < 2) {\n this.db.exec(SCHEMA_SQL_SQLITE_API_KEYS)\n this.db.exec('PRAGMA user_version = 2')\n }\n if (row.user_version < 3) {\n this.db.exec(SCHEMA_SQL_SQLITE_ENTERPRISE)\n this.db.exec('PRAGMA user_version = 3')\n }\n if (row.user_version < 4) {\n this.db.exec('ALTER TABLE user_roles ADD COLUMN tenant_id TEXT NOT NULL DEFAULT \\'default\\'')\n this.db.exec('PRAGMA user_version = 4')\n }\n if (row.user_version < 5) {\n this.db.exec(SCHEMA_SQL_SQLITE_TEMPLATES)\n this.db.exec('PRAGMA user_version = 5')\n }\n }\n\n // ── Profiles ──────────────────────────────────────────────────────────────\n\n private mapProfile(row: RawProfile): Profile {\n return {\n id: row.id,\n tenantId: row.tenant_id,\n name: row.name,\n defaultLocale: row.default_locale,\n version: row.version,\n profileJson: JSON.parse(row.profile_json) as ProfileConfig,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }\n }\n\n async createProfile(data: CreateProfileInput): Promise<Profile> {\n const id = randomProfileId()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO profiles (id,tenant_id,name,default_locale,profile_json,created_at,updated_at) VALUES (?,?,?,?,?,?,?)'\n ).run(id, data.tenantId, data.name, data.defaultLocale, JSON.stringify(data.profileJson), now, now)\n const profile = await this.getProfile(id)\n if (!profile) throw new Error('Failed to create profile')\n return profile\n }\n\n async updateProfile(id: string, data: UpdateProfileInput): Promise<Profile> {\n const existing = await this.getProfile(id)\n if (!existing) throw new Error(`Profile ${id} not found`)\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?', 'version = version + 1']\n const vals: (string | number | null)[] = [now]\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.defaultLocale != null) { fields.push('default_locale = ?'); vals.push(data.defaultLocale) }\n if (data.profileJson != null) { fields.push('profile_json = ?'); vals.push(JSON.stringify(data.profileJson)) }\n vals.push(id)\n this.stmt(`UPDATE profiles SET ${fields.join(', ')} WHERE id = ?`).run(...vals)\n const updated = await this.getProfile(id)\n if (!updated) throw new Error('Failed to update profile')\n return updated\n }\n\n async deleteProfile(id: string): Promise<void> {\n this.stmt('DELETE FROM profiles WHERE id = ?').run(id)\n }\n\n async getProfile(id: string): Promise<Profile | null> {\n const row = this.stmt('SELECT * FROM profiles WHERE id = ?').get(id) as RawProfile | undefined\n return row ? this.mapProfile(row) : null\n }\n\n async getProfiles(tenantId: string): Promise<Profile[]> {\n const rows = this.stmt('SELECT * FROM profiles WHERE tenant_id = ? ORDER BY created_at ASC').all(tenantId) as unknown as RawProfile[]\n return rows.map(r => this.mapProfile(r))\n }\n\n // ── Consents ──────────────────────────────────────────────────────────────\n\n private mapConsent(row: RawConsent): ConsentDbRecord {\n return {\n id: row.id,\n tenantId: row.tenant_id,\n visitorId: row.visitor_id,\n profileId: row.profile_id,\n profileVersion: row.profile_version,\n locale: row.locale,\n consentJson: JSON.parse(row.consent_json) as ConsentValue,\n gpcDetected: row.gpc_detected === 1,\n source: row.source as ConsentDbRecord['source'],\n ...(row.age_verified != null && row.age_verified !== 0 ? { ageVerified: true } : {}),\n ...(row.parental_consent_token != null ? { parentalConsentToken: row.parental_consent_token } : {}),\n ...(row.tcf_string != null ? { tcfString: row.tcf_string } : {}),\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }\n }\n\n async createConsent(data: CreateConsentInput): Promise<ConsentDbRecord> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO consent_records (id,tenant_id,visitor_id,profile_id,profile_version,locale,consent_json,gpc_detected,source,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)'\n ).run(id, data.tenantId, data.visitorId, data.profileId, data.profileVersion, data.locale, JSON.stringify(data.consentJson), data.gpcDetected ? 1 : 0, data.source, now, now)\n const histId = randomUUID()\n this.stmt(\n 'INSERT INTO consent_history (id,tenant_id,consent_record_id,visitor_id,old_json,new_json,action,created_at) VALUES (?,?,?,?,?,?,?,?)'\n ).run(histId, data.tenantId, id, data.visitorId, null, JSON.stringify(data.consentJson), 'created', now)\n const record = await this.getConsent(data.visitorId)\n if (!record) throw new Error('Failed to create consent')\n return record\n }\n\n async updateConsent(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord> {\n const existing = await this.getConsent(visitorId)\n if (!existing) throw new Error(`Consent for visitor ${visitorId} not found`)\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?', 'consent_json = ?']\n const vals: (string | number | null)[] = [now, JSON.stringify(data.consentJson)]\n if (data.locale != null) { fields.push('locale = ?'); vals.push(data.locale) }\n if (data.gpcDetected != null) { fields.push('gpc_detected = ?'); vals.push(data.gpcDetected ? 1 : 0) }\n vals.push(visitorId)\n this.stmt(`UPDATE consent_records SET ${fields.join(', ')} WHERE visitor_id = ?`).run(...vals)\n const histId = randomUUID()\n this.stmt(\n 'INSERT INTO consent_history (id,tenant_id,consent_record_id,visitor_id,old_json,new_json,action,created_at) VALUES (?,?,?,?,?,?,?,?)'\n ).run(histId, existing.tenantId, existing.id, visitorId, JSON.stringify(existing.consentJson), JSON.stringify(data.consentJson), 'updated', now)\n const updated = await this.getConsent(visitorId)\n if (!updated) throw new Error('Failed to update consent')\n return updated\n }\n\n async deleteConsent(visitorId: string): Promise<void> {\n this.stmt('DELETE FROM consent_history WHERE visitor_id = ?').run(visitorId)\n this.stmt('DELETE FROM consent_records WHERE visitor_id = ?').run(visitorId)\n }\n\n async getConsent(visitorId: string): Promise<ConsentDbRecord | null> {\n const row = this.stmt('SELECT * FROM consent_records WHERE visitor_id = ?').get(visitorId) as RawConsent | undefined\n return row ? this.mapConsent(row) : null\n }\n\n async getConsents(filters: ConsentFilters): Promise<ConsentDbRecord[]> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: (string | number | null)[] = [filters.tenantId]\n if (filters.profileId) { conditions.push('profile_id = ?'); vals.push(filters.profileId) }\n if (filters.from) { conditions.push('created_at >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('created_at <= ?'); vals.push(filters.to) }\n const limit = Math.min(filters.limit ?? 50, MAX_PAGE_SIZE)\n const offset = ((filters.page ?? 1) - 1) * limit\n vals.push(limit, offset)\n const rows = this.stmt(\n `SELECT * FROM consent_records WHERE ${conditions.join(' AND ')} ORDER BY created_at DESC LIMIT ? OFFSET ?`\n ).all(...vals) as unknown as RawConsent[]\n return rows.map(r => this.mapConsent(r))\n }\n\n async *streamConsents(filters: ConsentFilters): AsyncIterable<ConsentDbRecord> {\n const pageSize = 500\n let offset = 0\n while (true) {\n const rows = this.stmt(\n 'SELECT * FROM consent_records WHERE tenant_id = ? LIMIT ? OFFSET ?'\n ).all(filters.tenantId, pageSize, offset) as unknown as RawConsent[]\n if (rows.length === 0) break\n for (const row of rows) yield this.mapConsent(row)\n offset += pageSize\n }\n }\n\n async getConsentHistory(visitorId: string): Promise<ConsentHistoryEntry[]> {\n const rows = this.stmt(\n 'SELECT * FROM consent_history WHERE visitor_id = ? ORDER BY created_at ASC'\n ).all(visitorId) as unknown as RawConsentHistory[]\n return rows.map(r => ({\n id: r.id,\n tenantId: r.tenant_id,\n consentRecordId: r.consent_record_id,\n visitorId: r.visitor_id,\n oldJson: r.old_json != null ? JSON.parse(r.old_json) as ConsentValue : null,\n newJson: JSON.parse(r.new_json) as ConsentValue,\n action: r.action as ConsentHistoryEntry['action'],\n createdAt: r.created_at,\n }))\n }\n\n // ── Visitors ──────────────────────────────────────────────────────────────\n\n private mapVisitor(row: RawVisitor): Visitor {\n return {\n id: row.id,\n tenantId: row.tenant_id,\n visitorId: row.visitor_id,\n firstSeen: row.first_seen,\n lastSeen: row.last_seen,\n ...(row.country != null ? { country: row.country } : {}),\n ...(row.region != null ? { region: row.region } : {}),\n ...(row.city != null ? { city: row.city } : {}),\n ...(row.ip_hash != null ? { ipHash: row.ip_hash } : {}),\n ...(row.user_agent_hash != null ? { userAgentHash: row.user_agent_hash } : {}),\n }\n }\n\n async createVisitor(data: CreateVisitorInput): Promise<Visitor> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO visitors (id,tenant_id,visitor_id,country,region,city,ip_hash,user_agent_hash,first_seen,last_seen) VALUES (?,?,?,?,?,?,?,?,?,?)'\n ).run(id, data.tenantId, data.visitorId, data.country ?? null, data.region ?? null, data.city ?? null, data.ipHash ?? null, data.userAgentHash ?? null, now, now)\n const visitor = await this.getVisitor(data.visitorId)\n if (!visitor) throw new Error('Failed to create visitor')\n return visitor\n }\n\n async updateVisitor(visitorId: string, data: UpdateVisitorInput): Promise<Visitor> {\n const now = new Date().toISOString()\n const fields: string[] = ['last_seen = ?']\n const vals: (string | number | null)[] = [data.lastSeen ?? now]\n if (data.country != null) { fields.push('country = ?'); vals.push(data.country) }\n if (data.region != null) { fields.push('region = ?'); vals.push(data.region) }\n if (data.city != null) { fields.push('city = ?'); vals.push(data.city) }\n vals.push(visitorId)\n this.stmt(`UPDATE visitors SET ${fields.join(', ')} WHERE visitor_id = ?`).run(...vals)\n const visitor = await this.getVisitor(visitorId)\n if (!visitor) throw new Error(`Visitor ${visitorId} not found`)\n return visitor\n }\n\n async deleteVisitor(visitorId: string): Promise<void> {\n this.stmt('DELETE FROM visitors WHERE visitor_id = ?').run(visitorId)\n }\n\n async getVisitor(visitorId: string): Promise<Visitor | null> {\n const row = this.stmt('SELECT * FROM visitors WHERE visitor_id = ?').get(visitorId) as RawVisitor | undefined\n return row ? this.mapVisitor(row) : null\n }\n\n async getVisitors(filters: VisitorFilters): Promise<Visitor[]> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: (string | number | null)[] = [filters.tenantId]\n if (filters.from) { conditions.push('first_seen >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('first_seen <= ?'); vals.push(filters.to) }\n const limit = Math.min(filters.limit ?? 50, MAX_PAGE_SIZE)\n const offset = ((filters.page ?? 1) - 1) * limit\n vals.push(limit, offset)\n const rows = this.stmt(\n `SELECT * FROM visitors WHERE ${conditions.join(' AND ')} ORDER BY last_seen DESC LIMIT ? OFFSET ?`\n ).all(...vals) as unknown as RawVisitor[]\n return rows.map(r => this.mapVisitor(r))\n }\n\n // ── Users ─────────────────────────────────────────────────────────────────\n\n private mapUser(row: RawUser): AdminUser {\n return {\n id: row.id,\n tenantId: row.tenant_id,\n name: row.name,\n email: row.email,\n passwordHash: row.password_hash,\n isActive: row.is_active === 1,\n totpEnabled: row.totp_enabled === 1,\n ...(row.totp_secret != null ? { totpSecret: row.totp_secret } : {}),\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }\n }\n\n async createUser(data: CreateUserInput): Promise<AdminUser> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO users (id,tenant_id,name,email,password_hash,created_at,updated_at) VALUES (?,?,?,?,?,?,?)'\n ).run(id, data.tenantId, data.name, data.email, data.passwordHash, now, now)\n const user = await this.getUserByEmail(data.email)\n if (!user) throw new Error('Failed to create user')\n return user\n }\n\n async updateUser(id: string, data: UpdateUserInput): Promise<AdminUser> {\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?']\n const vals: (string | number | null)[] = [now]\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.email != null) { fields.push('email = ?'); vals.push(data.email) }\n if (data.passwordHash != null) { fields.push('password_hash = ?'); vals.push(data.passwordHash) }\n if (data.isActive != null) { fields.push('is_active = ?'); vals.push(data.isActive ? 1 : 0) }\n if ('totpSecret' in data) { fields.push('totp_secret = ?'); vals.push(data.totpSecret ?? null) }\n if (data.totpEnabled != null) { fields.push('totp_enabled = ?'); vals.push(data.totpEnabled ? 1 : 0) }\n vals.push(id)\n this.stmt(`UPDATE users SET ${fields.join(', ')} WHERE id = ?`).run(...vals)\n const row = this.stmt('SELECT * FROM users WHERE id = ?').get(id) as RawUser | undefined\n if (!row) throw new Error(`User ${id} not found`)\n return this.mapUser(row)\n }\n\n async deleteUser(id: string): Promise<void> {\n this.stmt('DELETE FROM user_roles WHERE user_id = ?').run(id)\n this.stmt('DELETE FROM users WHERE id = ?').run(id)\n }\n\n async getUserById(id: string): Promise<AdminUser | null> {\n const row = this.stmt('SELECT * FROM users WHERE id = ?').get(id) as RawUser | undefined\n return row ? this.mapUser(row) : null\n }\n\n async getUserByEmail(email: string): Promise<AdminUser | null> {\n const row = this.stmt('SELECT * FROM users WHERE email = ?').get(email) as RawUser | undefined\n return row ? this.mapUser(row) : null\n }\n\n async getUsers(tenantId: string): Promise<AdminUser[]> {\n const rows = this.stmt('SELECT * FROM users WHERE tenant_id = ? ORDER BY created_at ASC').all(tenantId) as unknown as RawUser[]\n return rows.map(r => this.mapUser(r))\n }\n\n async countUsers(tenantId?: string): Promise<number> {\n const row = tenantId\n ? this.stmt('SELECT COUNT(*) as n FROM users WHERE tenant_id = ?').get(tenantId) as { n: number } | undefined\n : this.stmt('SELECT COUNT(*) as n FROM users').get() as { n: number } | undefined\n return row?.n ?? 0\n }\n\n // ── Roles & Permissions ───────────────────────────────────────────────────\n\n async getRoles(tenantId: string): Promise<Role[]> {\n const rows = this.stmt('SELECT * FROM roles WHERE tenant_id = ?').all(tenantId) as unknown as RawRole[]\n return rows.map(r => ({\n id: r.id, tenantId: r.tenant_id, name: r.name,\n ...(r.description != null ? { description: r.description } : {}),\n }))\n }\n\n async createRole(data: CreateRoleInput): Promise<Role> {\n const id = randomUUID()\n this.stmt('INSERT INTO roles (id,tenant_id,name,description) VALUES (?,?,?,?)').run(\n id, data.tenantId, data.name, data.description ?? null\n )\n const row = this.stmt('SELECT * FROM roles WHERE id = ?').get(id) as RawRole | undefined\n if (!row) throw new Error('Failed to create role')\n return { id: row.id, tenantId: row.tenant_id, name: row.name, ...(row.description != null ? { description: row.description } : {}) }\n }\n\n async updateRole(id: string, data: UpdateRoleInput): Promise<Role> {\n const fields: string[] = []\n const vals: (string | number | null)[] = []\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.description != null) { fields.push('description = ?'); vals.push(data.description) }\n if (fields.length > 0) {\n vals.push(id)\n this.stmt(`UPDATE roles SET ${fields.join(', ')} WHERE id = ?`).run(...vals)\n }\n const row = this.stmt('SELECT * FROM roles WHERE id = ?').get(id) as RawRole | undefined\n if (!row) throw new Error(`Role ${id} not found`)\n return { id: row.id, tenantId: row.tenant_id, name: row.name, ...(row.description != null ? { description: row.description } : {}) }\n }\n\n async deleteRole(id: string): Promise<void> {\n this.stmt('DELETE FROM role_permissions WHERE role_id = ?').run(id)\n this.stmt('DELETE FROM user_roles WHERE role_id = ?').run(id)\n this.stmt('DELETE FROM roles WHERE id = ?').run(id)\n }\n\n async getAllPermissions(): Promise<Permission[]> {\n const rows = this.stmt('SELECT * FROM permissions ORDER BY name ASC').all() as unknown as RawPermission[]\n return rows.map(r => ({ id: r.id, name: r.name, ...(r.description != null ? { description: r.description } : {}) }))\n }\n\n async assignPermissionToRole(roleId: string, permissionId: string): Promise<void> {\n this.stmt('INSERT OR IGNORE INTO role_permissions (role_id,permission_id) VALUES (?,?)').run(roleId, permissionId)\n }\n\n async revokePermissionFromRole(roleId: string, permissionId: string): Promise<void> {\n this.stmt('DELETE FROM role_permissions WHERE role_id = ? AND permission_id = ?').run(roleId, permissionId)\n }\n\n async getPermissionsForRole(roleId: string): Promise<Permission[]> {\n const rows = this.stmt(\n 'SELECT p.* FROM permissions p JOIN role_permissions rp ON rp.permission_id = p.id WHERE rp.role_id = ?'\n ).all(roleId) as unknown as RawPermission[]\n return rows.map(r => ({\n id: r.id, name: r.name,\n ...(r.description != null ? { description: r.description } : {}),\n }))\n }\n\n async getUserRoles(userId: string, tenantId?: string): Promise<Role[]> {\n const rows = tenantId\n ? this.stmt(\n 'SELECT r.* FROM roles r JOIN user_roles ur ON ur.role_id = r.id WHERE ur.user_id = ? AND ur.tenant_id = ?'\n ).all(userId, tenantId) as unknown as RawRole[]\n : this.stmt(\n 'SELECT r.* FROM roles r JOIN user_roles ur ON ur.role_id = r.id WHERE ur.user_id = ?'\n ).all(userId) as unknown as RawRole[]\n return rows.map(r => ({\n id: r.id, tenantId: r.tenant_id, name: r.name,\n ...(r.description != null ? { description: r.description } : {}),\n }))\n }\n\n async assignRole(userId: string, roleId: string, tenantId = 'default'): Promise<void> {\n this.stmt('INSERT OR IGNORE INTO user_roles (user_id, role_id, tenant_id) VALUES (?,?,?)').run(userId, roleId, tenantId)\n }\n\n async revokeRole(userId: string, roleId: string, tenantId?: string): Promise<void> {\n if (tenantId) {\n this.stmt('DELETE FROM user_roles WHERE user_id = ? AND role_id = ? AND tenant_id = ?').run(userId, roleId, tenantId)\n } else {\n this.stmt('DELETE FROM user_roles WHERE user_id = ? AND role_id = ?').run(userId, roleId)\n }\n }\n\n // ── Audit ─────────────────────────────────────────────────────────────────\n\n async createLog(data: CreateAuditLogInput): Promise<void> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO audit_logs (id,tenant_id,user_id,action,resource_type,resource_id,old_data,new_data,created_at) VALUES (?,?,?,?,?,?,?,?,?)'\n ).run(\n id, data.tenantId, data.userId ?? null, data.action, data.resourceType,\n data.resourceId ?? null,\n data.oldData != null ? JSON.stringify(data.oldData) : null,\n data.newData != null ? JSON.stringify(data.newData) : null,\n now\n )\n }\n\n async getLogs(filters: AuditFilters): Promise<AuditLog[]> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: (string | number | null)[] = [filters.tenantId]\n if (filters.action) { conditions.push('action = ?'); vals.push(filters.action) }\n if (filters.resourceType) { conditions.push('resource_type = ?'); vals.push(filters.resourceType) }\n if (filters.from) { conditions.push('created_at >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('created_at <= ?'); vals.push(filters.to) }\n const limit = Math.min(filters.limit ?? 50, MAX_PAGE_SIZE)\n const offset = ((filters.page ?? 1) - 1) * limit\n vals.push(limit, offset)\n const rows = this.stmt(\n `SELECT * FROM audit_logs WHERE ${conditions.join(' AND ')} ORDER BY created_at DESC LIMIT ? OFFSET ?`\n ).all(...vals) as unknown as RawAuditLog[]\n return rows.map(r => this.mapAuditLog(r))\n }\n\n private mapAuditLog(r: RawAuditLog): AuditLog {\n return {\n id: r.id, tenantId: r.tenant_id, action: r.action,\n resourceType: r.resource_type, createdAt: r.created_at,\n ...(r.user_id != null ? { userId: r.user_id } : {}),\n ...(r.resource_id != null ? { resourceId: r.resource_id } : {}),\n ...(r.old_data != null ? { oldData: JSON.parse(r.old_data) as unknown } : {}),\n ...(r.new_data != null ? { newData: JSON.parse(r.new_data) as unknown } : {}),\n }\n }\n\n async *streamAuditLogs(filters: AuditFilters): AsyncIterable<AuditLog> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: (string | number | null)[] = [filters.tenantId]\n if (filters.action) { conditions.push('action = ?'); vals.push(filters.action) }\n if (filters.from) { conditions.push('created_at >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('created_at <= ?'); vals.push(filters.to) }\n const pageSize = 500\n let offset = 0\n while (true) {\n const rows = this.stmt(\n `SELECT * FROM audit_logs WHERE ${conditions.join(' AND ')} ORDER BY created_at DESC LIMIT ? OFFSET ?`\n ).all(...vals, pageSize, offset) as unknown as RawAuditLog[]\n if (rows.length === 0) break\n for (const row of rows) yield this.mapAuditLog(row)\n offset += pageSize\n }\n }\n\n // ── Stats ──────────────────────────────────────────────────────────────────\n\n async getOverviewStats(tenantId: string): Promise<OverviewStats> {\n const tc = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ?').get(tenantId) as { n: number } | undefined\n const gc = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ? AND gpc_detected = 1').get(tenantId) as { n: number } | undefined\n const vc = this.stmt('SELECT COUNT(*) as n FROM visitors WHERE tenant_id = ?').get(tenantId) as { n: number } | undefined\n const totalConsents = tc?.n ?? 0\n\n const recent = this.stmt(\n 'SELECT consent_json FROM consent_records WHERE tenant_id = ? ORDER BY created_at DESC LIMIT 500'\n ).all(tenantId) as unknown as { consent_json: string }[]\n\n let accepted = 0, rejected = 0\n for (const r of recent) {\n const vals = Object.values(JSON.parse(r.consent_json) as Record<string, string>)\n const grantedPct = vals.length > 0 ? vals.filter(v => v === 'granted').length / vals.length : 0\n if (grantedPct >= 0.8) accepted++\n else if (grantedPct <= 0.2) rejected++\n }\n const sample = recent.length || 1\n\n return {\n totalConsents,\n gpcDetectedCount: gc?.n ?? 0,\n totalVisitors: vc?.n ?? 0,\n acceptedPct: Math.round((accepted / sample) * 100),\n rejectedPct: Math.round((rejected / sample) * 100),\n }\n }\n\n async getCategoryStats(tenantId: string): Promise<CategoryStats> {\n const rows = this.stmt(\n 'SELECT consent_json FROM consent_records WHERE tenant_id = ? LIMIT 5000'\n ).all(tenantId) as unknown as { consent_json: string }[]\n const stats: CategoryStats = {}\n for (const row of rows) {\n const consent = JSON.parse(row.consent_json) as Record<string, string>\n for (const [key, status] of Object.entries(consent)) {\n if (!stats[key]) stats[key] = { granted: 0, denied: 0, objected: 0 }\n if (status === 'granted') stats[key]!.granted++\n else if (status === 'denied') stats[key]!.denied++\n else if (status === 'objected') stats[key]!.objected++\n }\n }\n return stats\n }\n\n async getTimeline(tenantId: string, days = 30): Promise<TimelineEntry[]> {\n const rows = this.stmt(\n `SELECT date(created_at) as date, COUNT(*) as count FROM consent_records WHERE tenant_id = ? AND created_at >= date('now', ?) GROUP BY date(created_at) ORDER BY date ASC`\n ).all(tenantId, `-${days} days`) as unknown as { date: string; count: number }[]\n return rows.map(r => ({ date: r.date, count: r.count }))\n }\n\n async getCountries(tenantId: string): Promise<CountryStat[]> {\n const rows = this.stmt(\n `SELECT v.country, COUNT(*) as count FROM consent_records cr JOIN visitors v ON v.visitor_id = cr.visitor_id WHERE cr.tenant_id = ? AND v.country IS NOT NULL GROUP BY v.country ORDER BY count DESC LIMIT 50`\n ).all(tenantId) as unknown as { country: string; count: number }[]\n return rows.map(r => ({ country: r.country, count: r.count }))\n }\n\n async getGpcStats(tenantId: string): Promise<GpcStats> {\n const total = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ?').get(tenantId) as { n: number } | undefined\n const detected = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ? AND gpc_detected = 1').get(tenantId) as { n: number } | undefined\n const t = total?.n ?? 0\n const d = detected?.n ?? 0\n return { detected: d, total: t, rate: t > 0 ? Math.round((d / t) * 100) : 0 }\n }\n\n // ── Tenants ────────────────────────────────────────────────────────────────\n\n async getTenants(): Promise<Tenant[]> {\n const rows = this.stmt('SELECT * FROM tenants ORDER BY name ASC').all() as unknown as RawTenant[]\n return rows.map(r => ({ id: r.id, name: r.name, slug: r.slug, createdAt: r.created_at, updatedAt: r.updated_at }))\n }\n\n async createTenant(data: CreateTenantInput): Promise<Tenant> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt('INSERT INTO tenants (id,name,slug,created_at,updated_at) VALUES (?,?,?,?,?)').run(id, data.name, data.slug, now, now)\n const row = this.stmt('SELECT * FROM tenants WHERE id = ?').get(id) as RawTenant | undefined\n if (!row) throw new Error('Failed to create tenant')\n return { id: row.id, name: row.name, slug: row.slug, createdAt: row.created_at, updatedAt: row.updated_at }\n }\n\n async updateTenant(id: string, data: UpdateTenantInput): Promise<Tenant> {\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?']\n const vals: (string | number)[] = [now]\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.slug != null) { fields.push('slug = ?'); vals.push(data.slug) }\n vals.push(id)\n this.stmt(`UPDATE tenants SET ${fields.join(', ')} WHERE id = ?`).run(...vals)\n const row = this.stmt('SELECT * FROM tenants WHERE id = ?').get(id) as RawTenant | undefined\n if (!row) throw new Error(`Tenant ${id} not found`)\n return { id: row.id, name: row.name, slug: row.slug, createdAt: row.created_at, updatedAt: row.updated_at }\n }\n\n async deleteTenant(id: string): Promise<void> {\n this.stmt('DELETE FROM tenants WHERE id = ?').run(id)\n }\n\n async purgeExpiredConsents(olderThanDays: number): Promise<number> {\n const cutoff = new Date(Date.now() - olderThanDays * 86_400_000).toISOString()\n const toDelete = this.stmt(\n 'SELECT visitor_id FROM consent_records WHERE created_at < ?'\n ).all(cutoff) as unknown as { visitor_id: string }[]\n for (const { visitor_id } of toDelete) {\n this.stmt('DELETE FROM consent_history WHERE visitor_id = ?').run(visitor_id)\n this.stmt('DELETE FROM consent_records WHERE visitor_id = ?').run(visitor_id)\n }\n return toDelete.length\n }\n\n // ── API Keys ───────────────────────────────────────────────────────────────\n\n private mapApiKey(r: RawApiKey): ApiKey {\n return { id: r.id, tenantId: r.tenant_id, keyHash: r.key_hash, name: r.name, isActive: r.is_active === 1, createdAt: r.created_at }\n }\n\n async createApiKey(data: CreateApiKeyInput): Promise<ApiKey> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt('INSERT INTO api_keys (id,tenant_id,key_hash,name,created_at) VALUES (?,?,?,?,?)').run(id, data.tenantId, data.keyHash, data.name, now)\n const row = this.stmt('SELECT * FROM api_keys WHERE id = ?').get(id) as RawApiKey | undefined\n if (!row) throw new Error('Failed to create API key')\n return this.mapApiKey(row)\n }\n\n async getApiKeyByHash(keyHash: string): Promise<ApiKey | null> {\n const row = this.stmt('SELECT * FROM api_keys WHERE key_hash = ? AND is_active = 1').get(keyHash) as RawApiKey | undefined\n return row ? this.mapApiKey(row) : null\n }\n\n async revokeApiKey(id: string): Promise<void> {\n this.stmt('UPDATE api_keys SET is_active = 0 WHERE id = ?').run(id)\n }\n\n async getApiKeys(tenantId: string): Promise<ApiKey[]> {\n const rows = this.stmt('SELECT * FROM api_keys WHERE tenant_id = ? ORDER BY created_at DESC').all(tenantId) as unknown as RawApiKey[]\n return rows.map(r => this.mapApiKey(r))\n }\n\n // ── Cookie Templates ───────────────────────────────────────────────────────\n\n private mapCookieTemplate(r: RawCookieTemplate): ServerCookieTemplate {\n return { id: r.id, tenantId: r.tenant_id, name: r.name, cookies: JSON.parse(r.cookies_json), createdAt: r.created_at, updatedAt: r.updated_at }\n }\n\n async createCookieTemplate(data: CreateCookieTemplateInput): Promise<ServerCookieTemplate> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt('INSERT INTO cookie_templates (id,tenant_id,name,cookies_json,created_at,updated_at) VALUES (?,?,?,?,?,?)').run(id, data.tenantId, data.name, JSON.stringify(data.cookies), now, now)\n return this.mapCookieTemplate(this.stmt('SELECT * FROM cookie_templates WHERE id = ?').get(id) as unknown as RawCookieTemplate)\n }\n\n async updateCookieTemplate(id: string, data: UpdateCookieTemplateInput): Promise<ServerCookieTemplate> {\n const now = new Date().toISOString()\n if (data.name !== undefined) this.stmt('UPDATE cookie_templates SET name = ?, updated_at = ? WHERE id = ?').run(data.name, now, id)\n if (data.cookies !== undefined) this.stmt('UPDATE cookie_templates SET cookies_json = ?, updated_at = ? WHERE id = ?').run(JSON.stringify(data.cookies), now, id)\n const row = this.stmt('SELECT * FROM cookie_templates WHERE id = ?').get(id) as RawCookieTemplate | undefined\n if (!row) throw new Error('Cookie template not found')\n return this.mapCookieTemplate(row)\n }\n\n async deleteCookieTemplate(id: string): Promise<void> {\n this.stmt('DELETE FROM cookie_templates WHERE id = ?').run(id)\n }\n\n async getCookieTemplate(id: string): Promise<ServerCookieTemplate | null> {\n const row = this.stmt('SELECT * FROM cookie_templates WHERE id = ?').get(id) as RawCookieTemplate | undefined\n return row ? this.mapCookieTemplate(row) : null\n }\n\n async getCookieTemplates(tenantId: string): Promise<ServerCookieTemplate[]> {\n const rows = this.stmt('SELECT * FROM cookie_templates WHERE tenant_id = ? ORDER BY name ASC').all(tenantId) as unknown as RawCookieTemplate[]\n return rows.map(r => this.mapCookieTemplate(r))\n }\n\n async copyCookieTemplate(id: string, newName: string): Promise<ServerCookieTemplate> {\n const src = await this.getCookieTemplate(id)\n if (!src) throw new Error('Cookie template not found')\n return this.createCookieTemplate({ tenantId: src.tenantId, name: newName, cookies: src.cookies })\n }\n\n // ── UI Templates ───────────────────────────────────────────────────────────\n\n private mapUITemplate(r: RawUITemplate): ServerUITemplate {\n const s = JSON.parse(r.settings_json) as Omit<ServerUITemplate, 'id' | 'tenantId' | 'name' | 'createdAt' | 'updatedAt'>\n return { id: r.id, tenantId: r.tenant_id, name: r.name, ...s, createdAt: r.created_at, updatedAt: r.updated_at }\n }\n\n async createUITemplate(data: CreateUITemplateInput): Promise<ServerUITemplate> {\n const id = randomUUID()\n const now = new Date().toISOString()\n const { tenantId, name, ...settings } = data\n this.stmt('INSERT INTO ui_templates (id,tenant_id,name,settings_json,created_at,updated_at) VALUES (?,?,?,?,?,?)').run(id, tenantId, name, JSON.stringify(settings), now, now)\n return this.mapUITemplate(this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as unknown as RawUITemplate)\n }\n\n async updateUITemplate(id: string, data: UpdateUITemplateInput): Promise<ServerUITemplate> {\n const now = new Date().toISOString()\n const row = this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as RawUITemplate | undefined\n if (!row) throw new Error('UI template not found')\n if (data.name !== undefined) this.stmt('UPDATE ui_templates SET name = ?, updated_at = ? WHERE id = ?').run(data.name, now, id)\n const { name: _n, ...settingsUpdate } = data\n if (Object.keys(settingsUpdate).length > 0) {\n const current = JSON.parse(row.settings_json) as Record<string, unknown>\n const merged = { ...current, ...settingsUpdate }\n this.stmt('UPDATE ui_templates SET settings_json = ?, updated_at = ? WHERE id = ?').run(JSON.stringify(merged), now, id)\n }\n return this.mapUITemplate(this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as unknown as RawUITemplate)\n }\n\n async deleteUITemplate(id: string): Promise<void> {\n this.stmt('DELETE FROM ui_templates WHERE id = ?').run(id)\n }\n\n async getUITemplate(id: string): Promise<ServerUITemplate | null> {\n const row = this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as RawUITemplate | undefined\n return row ? this.mapUITemplate(row) : null\n }\n\n async getUITemplates(tenantId: string): Promise<ServerUITemplate[]> {\n const rows = this.stmt('SELECT * FROM ui_templates WHERE tenant_id = ? ORDER BY name ASC').all(tenantId) as unknown as RawUITemplate[]\n return rows.map(r => this.mapUITemplate(r))\n }\n\n async copyUITemplate(id: string, newName: string): Promise<ServerUITemplate> {\n const src = await this.getUITemplate(id)\n if (!src) throw new Error('UI template not found')\n const { tenantId, mainBanner, gpcBanner, preferenceModal } = src\n return this.createUITemplate({ tenantId, name: newName, mainBanner, gpcBanner, preferenceModal })\n }\n}\n","import type { Database as DB, Statement } from 'node-sqlite3-wasm'\n\nconst MAX_PAGE_SIZE = 500\nimport { randomUUID, randomProfileId } from '../../utils/crypto'\nimport {\n SEED_SQL,\n SCHEMA_SQL_SQLITE,\n SCHEMA_SQL_SQLITE_API_KEYS,\n SCHEMA_SQL_SQLITE_ENTERPRISE,\n SCHEMA_SQL_SQLITE_TEMPLATES,\n} from '../seed-data'\nimport type {\n StorageAdapter,\n StorageConfig,\n Profile,\n ProfileConfig,\n CreateProfileInput,\n UpdateProfileInput,\n ConsentDbRecord,\n ConsentHistoryEntry,\n ConsentValue,\n CreateConsentInput,\n UpdateConsentInput,\n ConsentFilters,\n Visitor,\n VisitorFilters,\n CreateVisitorInput,\n UpdateVisitorInput,\n AdminUser,\n CreateUserInput,\n UpdateUserInput,\n Role,\n CreateRoleInput,\n UpdateRoleInput,\n Permission,\n AuditLog,\n AuditFilters,\n CreateAuditLogInput,\n OverviewStats,\n CategoryStats,\n TimelineEntry,\n CountryStat,\n GpcStats,\n Tenant,\n ApiKey,\n CreateApiKeyInput,\n CreateTenantInput,\n UpdateTenantInput,\n ServerCookieTemplate,\n ServerUITemplate,\n CreateCookieTemplateInput,\n UpdateCookieTemplateInput,\n CreateUITemplateInput,\n UpdateUITemplateInput,\n} from '@consenti/types'\n\ninterface RawProfile {\n id: string; tenant_id: string; name: string; default_locale: string\n version: number; profile_json: string\n created_at: string; updated_at: string\n}\ninterface RawConsent {\n id: string; tenant_id: string; visitor_id: string; profile_id: string\n profile_version: number; locale: string; consent_json: string\n gpc_detected: number; source: string; created_at: string; updated_at: string\n age_verified?: number; parental_consent_token?: string | null; tcf_string?: string | null\n}\ninterface RawConsentHistory {\n id: string; tenant_id: string; consent_record_id: string; visitor_id: string\n old_json: string | null; new_json: string; action: string; created_at: string\n}\ninterface RawVisitor {\n id: string; tenant_id: string; visitor_id: string\n country: string | null; region: string | null; city: string | null\n ip_hash: string | null; user_agent_hash: string | null\n first_seen: string; last_seen: string\n}\ninterface RawUser {\n id: string; tenant_id: string; name: string; email: string\n password_hash: string; is_active: number; created_at: string; updated_at: string\n totp_secret?: string | null; totp_enabled?: number\n}\ninterface RawRole {\n id: string; tenant_id: string; name: string; description: string | null\n}\ninterface RawPermission {\n id: string; name: string; description: string | null\n}\ninterface RawAuditLog {\n id: string; tenant_id: string; user_id: string | null; action: string\n resource_type: string; resource_id: string | null\n old_data: string | null; new_data: string | null; created_at: string\n}\ninterface RawTenant {\n id: string; name: string; slug: string; created_at: string; updated_at: string\n}\ninterface RawApiKey {\n id: string; tenant_id: string; key_hash: string; name: string; is_active: number; created_at: string\n}\ninterface RawCookieTemplate {\n id: string; tenant_id: string; name: string; cookies_json: string; created_at: string; updated_at: string\n}\ninterface RawUITemplate {\n id: string; tenant_id: string; name: string; settings_json: string; created_at: string; updated_at: string\n}\n\n\n// node-sqlite3-wasm statements are NOT garbage-collected — they must be\n// finalized explicitly. All cached statements are finalized in disconnect().\n// Parameter binding uses run(array) / all(array) — not spread — per the WASM API.\n\ntype Val = string | number | null\n\nexport class NodeSqlite3WasmAdapter implements StorageAdapter {\n private db!: DB\n private cache = new Map<string, Statement>()\n\n constructor(private config: StorageConfig) { }\n\n private stmt(sql: string): Statement {\n let s = this.cache.get(sql)\n if (!s) { s = this.db.prepare(sql); this.cache.set(sql, s) }\n return s\n }\n\n async connect(): Promise<void> {\n // Lazy: only loaded when this driver is actually selected — allows the package\n // to be an optional peer dep without crashing on startup for other drivers.\n const mod = await import('node-sqlite3-wasm').catch(() => {\n throw new Error(\"driver 'node-sqlite3-wasm' requires: npm install node-sqlite3-wasm\")\n }) as { default: { Database: new (path: string) => DB } }\n this.db = new mod.default.Database(this.config.path ?? './consenti.db')\n this.db.exec('PRAGMA journal_mode=WAL')\n this.db.exec('PRAGMA foreign_keys=ON')\n this.db.exec('PRAGMA synchronous=NORMAL')\n await this.migrate()\n }\n\n async disconnect(): Promise<void> {\n // Finalize all prepared statements before closing — WASM objects are not\n // GC'd and will leak if not explicitly freed.\n for (const stmt of this.cache.values()) {\n stmt.finalize()\n }\n this.cache.clear()\n this.db.close()\n }\n\n async migrate(): Promise<void> {\n const row = this.stmt('PRAGMA user_version').get() as { user_version: number } | null\n const ver = row?.user_version ?? 0\n if (ver < 1) {\n this.db.exec(SCHEMA_SQL_SQLITE)\n this.db.exec(SEED_SQL)\n this.db.exec('PRAGMA user_version = 1')\n }\n if (ver < 2) {\n this.db.exec(SCHEMA_SQL_SQLITE_API_KEYS)\n this.db.exec('PRAGMA user_version = 2')\n }\n if (ver < 3) {\n this.db.exec(SCHEMA_SQL_SQLITE_ENTERPRISE)\n this.db.exec('PRAGMA user_version = 3')\n }\n if (ver < 4) {\n this.db.exec('ALTER TABLE user_roles ADD COLUMN tenant_id TEXT NOT NULL DEFAULT \\'default\\'')\n this.db.exec('PRAGMA user_version = 4')\n }\n if (ver < 5) {\n this.db.exec(SCHEMA_SQL_SQLITE_TEMPLATES)\n this.db.exec('PRAGMA user_version = 5')\n }\n }\n\n // ── Profiles ──────────────────────────────────────────────────────────────\n\n private mapProfile(row: RawProfile): Profile {\n return {\n id: row.id, tenantId: row.tenant_id, name: row.name,\n defaultLocale: row.default_locale, version: row.version,\n profileJson: JSON.parse(row.profile_json) as ProfileConfig,\n createdAt: row.created_at, updatedAt: row.updated_at,\n }\n }\n\n async createProfile(data: CreateProfileInput): Promise<Profile> {\n const id = randomProfileId()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO profiles (id,tenant_id,name,default_locale,profile_json,created_at,updated_at) VALUES (?,?,?,?,?,?,?)'\n ).run([id, data.tenantId, data.name, data.defaultLocale, JSON.stringify(data.profileJson), now, now])\n const profile = await this.getProfile(id)\n if (!profile) throw new Error('Failed to create profile')\n return profile\n }\n\n async updateProfile(id: string, data: UpdateProfileInput): Promise<Profile> {\n const existing = await this.getProfile(id)\n if (!existing) throw new Error(`Profile ${id} not found`)\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?', 'version = version + 1']\n const vals: Val[] = [now]\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.defaultLocale != null) { fields.push('default_locale = ?'); vals.push(data.defaultLocale) }\n if (data.profileJson != null) { fields.push('profile_json = ?'); vals.push(JSON.stringify(data.profileJson)) }\n vals.push(id)\n this.stmt(`UPDATE profiles SET ${fields.join(', ')} WHERE id = ?`).run(vals)\n const updated = await this.getProfile(id)\n if (!updated) throw new Error('Failed to update profile')\n return updated\n }\n\n async deleteProfile(id: string): Promise<void> {\n this.stmt('DELETE FROM profiles WHERE id = ?').run(id)\n }\n\n async getProfile(id: string): Promise<Profile | null> {\n const row = this.stmt('SELECT * FROM profiles WHERE id = ?').get(id) as RawProfile | null\n return row ? this.mapProfile(row) : null\n }\n\n async getProfiles(tenantId: string): Promise<Profile[]> {\n const rows = this.stmt('SELECT * FROM profiles WHERE tenant_id = ? ORDER BY created_at ASC').all(tenantId) as unknown as RawProfile[]\n return rows.map(r => this.mapProfile(r))\n }\n\n // ── Consents ──────────────────────────────────────────────────────────────\n\n private mapConsent(row: RawConsent): ConsentDbRecord {\n return {\n id: row.id, tenantId: row.tenant_id, visitorId: row.visitor_id,\n profileId: row.profile_id, profileVersion: row.profile_version,\n locale: row.locale, consentJson: JSON.parse(row.consent_json) as ConsentValue,\n gpcDetected: row.gpc_detected === 1,\n source: row.source as ConsentDbRecord['source'],\n ...(row.age_verified != null && row.age_verified !== 0 ? { ageVerified: true } : {}),\n ...(row.parental_consent_token != null ? { parentalConsentToken: row.parental_consent_token } : {}),\n ...(row.tcf_string != null ? { tcfString: row.tcf_string } : {}),\n createdAt: row.created_at, updatedAt: row.updated_at,\n }\n }\n\n async createConsent(data: CreateConsentInput): Promise<ConsentDbRecord> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO consent_records (id,tenant_id,visitor_id,profile_id,profile_version,locale,consent_json,gpc_detected,source,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)'\n ).run([id, data.tenantId, data.visitorId, data.profileId, data.profileVersion, data.locale, JSON.stringify(data.consentJson), data.gpcDetected ? 1 : 0, data.source, now, now])\n const histId = randomUUID()\n this.stmt(\n 'INSERT INTO consent_history (id,tenant_id,consent_record_id,visitor_id,old_json,new_json,action,created_at) VALUES (?,?,?,?,?,?,?,?)'\n ).run([histId, data.tenantId, id, data.visitorId, null, JSON.stringify(data.consentJson), 'created', now])\n const record = await this.getConsent(data.visitorId)\n if (!record) throw new Error('Failed to create consent')\n return record\n }\n\n async updateConsent(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord> {\n const existing = await this.getConsent(visitorId)\n if (!existing) throw new Error(`Consent for visitor ${visitorId} not found`)\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?', 'consent_json = ?']\n const vals: Val[] = [now, JSON.stringify(data.consentJson)]\n if (data.locale != null) { fields.push('locale = ?'); vals.push(data.locale) }\n if (data.gpcDetected != null) { fields.push('gpc_detected = ?'); vals.push(data.gpcDetected ? 1 : 0) }\n vals.push(visitorId)\n this.stmt(`UPDATE consent_records SET ${fields.join(', ')} WHERE visitor_id = ?`).run(vals)\n const histId = randomUUID()\n this.stmt(\n 'INSERT INTO consent_history (id,tenant_id,consent_record_id,visitor_id,old_json,new_json,action,created_at) VALUES (?,?,?,?,?,?,?,?)'\n ).run([histId, existing.tenantId, existing.id, visitorId, JSON.stringify(existing.consentJson), JSON.stringify(data.consentJson), 'updated', now])\n const updated = await this.getConsent(visitorId)\n if (!updated) throw new Error('Failed to update consent')\n return updated\n }\n\n async deleteConsent(visitorId: string): Promise<void> {\n this.stmt('DELETE FROM consent_history WHERE visitor_id = ?').run(visitorId)\n this.stmt('DELETE FROM consent_records WHERE visitor_id = ?').run(visitorId)\n }\n\n async getConsent(visitorId: string): Promise<ConsentDbRecord | null> {\n const row = this.stmt('SELECT * FROM consent_records WHERE visitor_id = ?').get(visitorId) as RawConsent | null\n return row ? this.mapConsent(row) : null\n }\n\n async getConsents(filters: ConsentFilters): Promise<ConsentDbRecord[]> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: Val[] = [filters.tenantId]\n if (filters.profileId) { conditions.push('profile_id = ?'); vals.push(filters.profileId) }\n if (filters.from) { conditions.push('created_at >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('created_at <= ?'); vals.push(filters.to) }\n const limit = Math.min(filters.limit ?? 50, MAX_PAGE_SIZE)\n const offset = ((filters.page ?? 1) - 1) * limit\n const rows = this.stmt(\n `SELECT * FROM consent_records WHERE ${conditions.join(' AND ')} ORDER BY created_at DESC LIMIT ? OFFSET ?`\n ).all([...vals, limit, offset]) as unknown as RawConsent[]\n return rows.map(r => this.mapConsent(r))\n }\n\n async *streamConsents(filters: ConsentFilters): AsyncIterable<ConsentDbRecord> {\n const pageSize = 500\n let offset = 0\n while (true) {\n const rows = this.stmt(\n 'SELECT * FROM consent_records WHERE tenant_id = ? LIMIT ? OFFSET ?'\n ).all([filters.tenantId, pageSize, offset]) as unknown as RawConsent[]\n if (rows.length === 0) break\n for (const row of rows) yield this.mapConsent(row)\n offset += pageSize\n }\n }\n\n async getConsentHistory(visitorId: string): Promise<ConsentHistoryEntry[]> {\n const rows = this.stmt(\n 'SELECT * FROM consent_history WHERE visitor_id = ? ORDER BY created_at ASC'\n ).all(visitorId) as unknown as RawConsentHistory[]\n return rows.map(r => ({\n id: r.id, tenantId: r.tenant_id, consentRecordId: r.consent_record_id,\n visitorId: r.visitor_id,\n oldJson: r.old_json != null ? JSON.parse(r.old_json) as ConsentValue : null,\n newJson: JSON.parse(r.new_json) as ConsentValue,\n action: r.action as ConsentHistoryEntry['action'],\n createdAt: r.created_at,\n }))\n }\n\n // ── Visitors ──────────────────────────────────────────────────────────────\n\n private mapVisitor(row: RawVisitor): Visitor {\n return {\n id: row.id, tenantId: row.tenant_id, visitorId: row.visitor_id,\n firstSeen: row.first_seen, lastSeen: row.last_seen,\n ...(row.country != null ? { country: row.country } : {}),\n ...(row.region != null ? { region: row.region } : {}),\n ...(row.city != null ? { city: row.city } : {}),\n ...(row.ip_hash != null ? { ipHash: row.ip_hash } : {}),\n ...(row.user_agent_hash != null ? { userAgentHash: row.user_agent_hash } : {}),\n }\n }\n\n async createVisitor(data: CreateVisitorInput): Promise<Visitor> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO visitors (id,tenant_id,visitor_id,country,region,city,ip_hash,user_agent_hash,first_seen,last_seen) VALUES (?,?,?,?,?,?,?,?,?,?)'\n ).run([id, data.tenantId, data.visitorId, data.country ?? null, data.region ?? null, data.city ?? null, data.ipHash ?? null, data.userAgentHash ?? null, now, now])\n const visitor = await this.getVisitor(data.visitorId)\n if (!visitor) throw new Error('Failed to create visitor')\n return visitor\n }\n\n async updateVisitor(visitorId: string, data: UpdateVisitorInput): Promise<Visitor> {\n const now = new Date().toISOString()\n const fields: string[] = ['last_seen = ?']\n const vals: Val[] = [data.lastSeen ?? now]\n if (data.country != null) { fields.push('country = ?'); vals.push(data.country) }\n if (data.region != null) { fields.push('region = ?'); vals.push(data.region) }\n if (data.city != null) { fields.push('city = ?'); vals.push(data.city) }\n vals.push(visitorId)\n this.stmt(`UPDATE visitors SET ${fields.join(', ')} WHERE visitor_id = ?`).run(vals)\n const visitor = await this.getVisitor(visitorId)\n if (!visitor) throw new Error(`Visitor ${visitorId} not found`)\n return visitor\n }\n\n async deleteVisitor(visitorId: string): Promise<void> {\n this.stmt('DELETE FROM visitors WHERE visitor_id = ?').run(visitorId)\n }\n\n async getVisitor(visitorId: string): Promise<Visitor | null> {\n const row = this.stmt('SELECT * FROM visitors WHERE visitor_id = ?').get(visitorId) as RawVisitor | null\n return row ? this.mapVisitor(row) : null\n }\n\n async getVisitors(filters: VisitorFilters): Promise<Visitor[]> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: Val[] = [filters.tenantId]\n if (filters.from) { conditions.push('first_seen >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('first_seen <= ?'); vals.push(filters.to) }\n const limit = Math.min(filters.limit ?? 50, MAX_PAGE_SIZE)\n const offset = ((filters.page ?? 1) - 1) * limit\n const rows = this.stmt(\n `SELECT * FROM visitors WHERE ${conditions.join(' AND ')} ORDER BY last_seen DESC LIMIT ? OFFSET ?`\n ).all([...vals, limit, offset]) as unknown as RawVisitor[]\n return rows.map(r => this.mapVisitor(r))\n }\n\n // ── Users ─────────────────────────────────────────────────────────────────\n\n private mapUser(row: RawUser): AdminUser {\n return {\n id: row.id, tenantId: row.tenant_id, name: row.name, email: row.email,\n passwordHash: row.password_hash, isActive: row.is_active === 1,\n totpEnabled: row.totp_enabled === 1,\n ...(row.totp_secret != null ? { totpSecret: row.totp_secret } : {}),\n createdAt: row.created_at, updatedAt: row.updated_at,\n }\n }\n\n async createUser(data: CreateUserInput): Promise<AdminUser> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO users (id,tenant_id,name,email,password_hash,created_at,updated_at) VALUES (?,?,?,?,?,?,?)'\n ).run([id, data.tenantId, data.name, data.email, data.passwordHash, now, now])\n const user = await this.getUserByEmail(data.email)\n if (!user) throw new Error('Failed to create user')\n return user\n }\n\n async updateUser(id: string, data: UpdateUserInput): Promise<AdminUser> {\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?']\n const vals: Val[] = [now]\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.email != null) { fields.push('email = ?'); vals.push(data.email) }\n if (data.passwordHash != null) { fields.push('password_hash = ?'); vals.push(data.passwordHash) }\n if (data.isActive != null) { fields.push('is_active = ?'); vals.push(data.isActive ? 1 : 0) }\n if ('totpSecret' in data) { fields.push('totp_secret = ?'); vals.push(data.totpSecret ?? null) }\n if (data.totpEnabled != null) { fields.push('totp_enabled = ?'); vals.push(data.totpEnabled ? 1 : 0) }\n vals.push(id)\n this.stmt(`UPDATE users SET ${fields.join(', ')} WHERE id = ?`).run(vals)\n const row = this.stmt('SELECT * FROM users WHERE id = ?').get(id) as RawUser | null\n if (!row) throw new Error(`User ${id} not found`)\n return this.mapUser(row)\n }\n\n async deleteUser(id: string): Promise<void> {\n this.stmt('DELETE FROM user_roles WHERE user_id = ?').run(id)\n this.stmt('DELETE FROM users WHERE id = ?').run(id)\n }\n\n async getUserById(id: string): Promise<AdminUser | null> {\n const row = this.stmt('SELECT * FROM users WHERE id = ?').get(id) as RawUser | null\n return row ? this.mapUser(row) : null\n }\n\n async getUserByEmail(email: string): Promise<AdminUser | null> {\n const row = this.stmt('SELECT * FROM users WHERE email = ?').get(email) as RawUser | null\n return row ? this.mapUser(row) : null\n }\n\n async getUsers(tenantId: string): Promise<AdminUser[]> {\n const rows = this.stmt('SELECT * FROM users WHERE tenant_id = ? ORDER BY created_at ASC').all(tenantId) as unknown as RawUser[]\n return rows.map(r => this.mapUser(r))\n }\n\n async countUsers(tenantId?: string): Promise<number> {\n const row = tenantId\n ? this.stmt('SELECT COUNT(*) as n FROM users WHERE tenant_id = ?').get(tenantId) as { n: number } | null\n : this.stmt('SELECT COUNT(*) as n FROM users').get() as { n: number } | null\n return row?.n ?? 0\n }\n\n // ── Roles & Permissions ───────────────────────────────────────────────────\n\n async getRoles(tenantId: string): Promise<Role[]> {\n const rows = this.stmt('SELECT * FROM roles WHERE tenant_id = ?').all(tenantId) as unknown as RawRole[]\n return rows.map(r => ({ id: r.id, tenantId: r.tenant_id, name: r.name, ...(r.description != null ? { description: r.description } : {}) }))\n }\n\n async createRole(data: CreateRoleInput): Promise<Role> {\n const id = randomUUID()\n this.stmt('INSERT INTO roles (id,tenant_id,name,description) VALUES (?,?,?,?)').run(\n [id, data.tenantId, data.name, data.description ?? null]\n )\n const row = this.stmt('SELECT * FROM roles WHERE id = ?').get(id) as RawRole | null\n if (!row) throw new Error('Failed to create role')\n return { id: row.id, tenantId: row.tenant_id, name: row.name, ...(row.description != null ? { description: row.description } : {}) }\n }\n\n async updateRole(id: string, data: UpdateRoleInput): Promise<Role> {\n const fields: string[] = []\n const vals: Val[] = []\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.description != null) { fields.push('description = ?'); vals.push(data.description) }\n if (fields.length > 0) {\n vals.push(id)\n this.stmt(`UPDATE roles SET ${fields.join(', ')} WHERE id = ?`).run(vals)\n }\n const row = this.stmt('SELECT * FROM roles WHERE id = ?').get(id) as RawRole | null\n if (!row) throw new Error(`Role ${id} not found`)\n return { id: row.id, tenantId: row.tenant_id, name: row.name, ...(row.description != null ? { description: row.description } : {}) }\n }\n\n async deleteRole(id: string): Promise<void> {\n this.stmt('DELETE FROM role_permissions WHERE role_id = ?').run(id)\n this.stmt('DELETE FROM user_roles WHERE role_id = ?').run(id)\n this.stmt('DELETE FROM roles WHERE id = ?').run(id)\n }\n\n async getAllPermissions(): Promise<Permission[]> {\n const rows = this.stmt('SELECT * FROM permissions ORDER BY name ASC').all() as unknown as RawPermission[]\n return rows.map(r => ({ id: r.id, name: r.name, ...(r.description != null ? { description: r.description } : {}) }))\n }\n\n async assignPermissionToRole(roleId: string, permissionId: string): Promise<void> {\n this.stmt('INSERT OR IGNORE INTO role_permissions (role_id,permission_id) VALUES (?,?)').run([roleId, permissionId])\n }\n\n async revokePermissionFromRole(roleId: string, permissionId: string): Promise<void> {\n this.stmt('DELETE FROM role_permissions WHERE role_id = ? AND permission_id = ?').run([roleId, permissionId])\n }\n\n async getPermissionsForRole(roleId: string): Promise<Permission[]> {\n const rows = this.stmt(\n 'SELECT p.* FROM permissions p JOIN role_permissions rp ON rp.permission_id = p.id WHERE rp.role_id = ?'\n ).all(roleId) as unknown as RawPermission[]\n return rows.map(r => ({ id: r.id, name: r.name, ...(r.description != null ? { description: r.description } : {}) }))\n }\n\n async getUserRoles(userId: string, tenantId?: string): Promise<Role[]> {\n const rows = tenantId\n ? this.stmt(\n 'SELECT r.* FROM roles r JOIN user_roles ur ON ur.role_id = r.id WHERE ur.user_id = ? AND ur.tenant_id = ?'\n ).all([userId, tenantId]) as unknown as RawRole[]\n : this.stmt(\n 'SELECT r.* FROM roles r JOIN user_roles ur ON ur.role_id = r.id WHERE ur.user_id = ?'\n ).all(userId) as unknown as RawRole[]\n return rows.map(r => ({ id: r.id, tenantId: r.tenant_id, name: r.name, ...(r.description != null ? { description: r.description } : {}) }))\n }\n\n async assignRole(userId: string, roleId: string, tenantId = 'default'): Promise<void> {\n this.stmt('INSERT OR IGNORE INTO user_roles (user_id, role_id, tenant_id) VALUES (?,?,?)').run([userId, roleId, tenantId])\n }\n\n async revokeRole(userId: string, roleId: string, tenantId?: string): Promise<void> {\n if (tenantId) {\n this.stmt('DELETE FROM user_roles WHERE user_id = ? AND role_id = ? AND tenant_id = ?').run([userId, roleId, tenantId])\n } else {\n this.stmt('DELETE FROM user_roles WHERE user_id = ? AND role_id = ?').run([userId, roleId])\n }\n }\n\n // ── Audit ─────────────────────────────────────────────────────────────────\n\n async createLog(data: CreateAuditLogInput): Promise<void> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO audit_logs (id,tenant_id,user_id,action,resource_type,resource_id,old_data,new_data,created_at) VALUES (?,?,?,?,?,?,?,?,?)'\n ).run([\n id, data.tenantId, data.userId ?? null, data.action, data.resourceType,\n data.resourceId ?? null,\n data.oldData != null ? JSON.stringify(data.oldData) : null,\n data.newData != null ? JSON.stringify(data.newData) : null,\n now,\n ])\n }\n\n async getLogs(filters: AuditFilters): Promise<AuditLog[]> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: Val[] = [filters.tenantId]\n if (filters.action) { conditions.push('action = ?'); vals.push(filters.action) }\n if (filters.resourceType) { conditions.push('resource_type = ?'); vals.push(filters.resourceType) }\n if (filters.from) { conditions.push('created_at >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('created_at <= ?'); vals.push(filters.to) }\n const limit = Math.min(filters.limit ?? 50, MAX_PAGE_SIZE)\n const offset = ((filters.page ?? 1) - 1) * limit\n const rows = this.stmt(\n `SELECT * FROM audit_logs WHERE ${conditions.join(' AND ')} ORDER BY created_at DESC LIMIT ? OFFSET ?`\n ).all([...vals, limit, offset]) as unknown as RawAuditLog[]\n return rows.map(r => this.mapAuditLog(r))\n }\n\n private mapAuditLog(r: RawAuditLog): AuditLog {\n return {\n id: r.id, tenantId: r.tenant_id, action: r.action,\n resourceType: r.resource_type, createdAt: r.created_at,\n ...(r.user_id != null ? { userId: r.user_id } : {}),\n ...(r.resource_id != null ? { resourceId: r.resource_id } : {}),\n ...(r.old_data != null ? { oldData: JSON.parse(r.old_data) as unknown } : {}),\n ...(r.new_data != null ? { newData: JSON.parse(r.new_data) as unknown } : {}),\n }\n }\n\n async *streamAuditLogs(filters: AuditFilters): AsyncIterable<AuditLog> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: Val[] = [filters.tenantId]\n if (filters.action) { conditions.push('action = ?'); vals.push(filters.action) }\n if (filters.from) { conditions.push('created_at >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('created_at <= ?'); vals.push(filters.to) }\n const pageSize = 500\n let offset = 0\n while (true) {\n const rows = this.stmt(\n `SELECT * FROM audit_logs WHERE ${conditions.join(' AND ')} ORDER BY created_at DESC LIMIT ? OFFSET ?`\n ).all([...vals, pageSize, offset]) as unknown as RawAuditLog[]\n if (rows.length === 0) break\n for (const row of rows) yield this.mapAuditLog(row)\n offset += pageSize\n }\n }\n\n // ── Stats ──────────────────────────────────────────────────────────────────\n\n async getOverviewStats(tenantId: string): Promise<OverviewStats> {\n const tc = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ?').get(tenantId) as { n: number } | null\n const gc = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ? AND gpc_detected = 1').get(tenantId) as { n: number } | null\n const vc = this.stmt('SELECT COUNT(*) as n FROM visitors WHERE tenant_id = ?').get(tenantId) as { n: number } | null\n const totalConsents = tc?.n ?? 0\n\n const recent = this.stmt(\n 'SELECT consent_json FROM consent_records WHERE tenant_id = ? ORDER BY created_at DESC LIMIT 500'\n ).all(tenantId) as unknown as { consent_json: string }[]\n\n let accepted = 0, rejected = 0\n for (const r of recent) {\n const vals = Object.values(JSON.parse(r.consent_json) as Record<string, string>)\n const grantedPct = vals.length > 0 ? vals.filter(v => v === 'granted').length / vals.length : 0\n if (grantedPct >= 0.8) accepted++\n else if (grantedPct <= 0.2) rejected++\n }\n const sample = recent.length || 1\n\n return {\n totalConsents,\n gpcDetectedCount: gc?.n ?? 0,\n totalVisitors: vc?.n ?? 0,\n acceptedPct: Math.round((accepted / sample) * 100),\n rejectedPct: Math.round((rejected / sample) * 100),\n }\n }\n\n async getCategoryStats(tenantId: string): Promise<CategoryStats> {\n const rows = this.stmt(\n 'SELECT consent_json FROM consent_records WHERE tenant_id = ? LIMIT 5000'\n ).all(tenantId) as unknown as { consent_json: string }[]\n const stats: CategoryStats = {}\n for (const row of rows) {\n const consent = JSON.parse(row.consent_json) as Record<string, string>\n for (const [key, status] of Object.entries(consent)) {\n if (!stats[key]) stats[key] = { granted: 0, denied: 0, objected: 0 }\n if (status === 'granted') stats[key]!.granted++\n else if (status === 'denied') stats[key]!.denied++\n else if (status === 'objected') stats[key]!.objected++\n }\n }\n return stats\n }\n\n async getTimeline(tenantId: string, days = 30): Promise<TimelineEntry[]> {\n const rows = this.stmt(\n `SELECT date(created_at) as date, COUNT(*) as count FROM consent_records WHERE tenant_id = ? AND created_at >= date('now', ?) GROUP BY date(created_at) ORDER BY date ASC`\n ).all([tenantId, `-${days} days`]) as unknown as { date: string; count: number }[]\n return rows.map(r => ({ date: r.date, count: r.count }))\n }\n\n async getCountries(tenantId: string): Promise<CountryStat[]> {\n const rows = this.stmt(\n `SELECT v.country, COUNT(*) as count FROM consent_records cr JOIN visitors v ON v.visitor_id = cr.visitor_id WHERE cr.tenant_id = ? AND v.country IS NOT NULL GROUP BY v.country ORDER BY count DESC LIMIT 50`\n ).all(tenantId) as unknown as { country: string; count: number }[]\n return rows.map(r => ({ country: r.country, count: r.count }))\n }\n\n async getGpcStats(tenantId: string): Promise<GpcStats> {\n const total = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ?').get(tenantId) as { n: number } | null\n const detected = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ? AND gpc_detected = 1').get(tenantId) as { n: number } | null\n const t = total?.n ?? 0\n const d = detected?.n ?? 0\n return { detected: d, total: t, rate: t > 0 ? Math.round((d / t) * 100) : 0 }\n }\n\n // ── Tenants ────────────────────────────────────────────────────────────────\n\n async getTenants(): Promise<Tenant[]> {\n const rows = this.stmt('SELECT * FROM tenants ORDER BY name ASC').all() as unknown as RawTenant[]\n return rows.map(r => ({ id: r.id, name: r.name, slug: r.slug, createdAt: r.created_at, updatedAt: r.updated_at }))\n }\n\n async createTenant(data: CreateTenantInput): Promise<Tenant> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt('INSERT INTO tenants (id,name,slug,created_at,updated_at) VALUES (?,?,?,?,?)').run([id, data.name, data.slug, now, now])\n const row = this.stmt('SELECT * FROM tenants WHERE id = ?').get(id) as RawTenant | null\n if (!row) throw new Error('Failed to create tenant')\n return { id: row.id, name: row.name, slug: row.slug, createdAt: row.created_at, updatedAt: row.updated_at }\n }\n\n async updateTenant(id: string, data: UpdateTenantInput): Promise<Tenant> {\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?']\n const vals: Val[] = [now]\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.slug != null) { fields.push('slug = ?'); vals.push(data.slug) }\n vals.push(id)\n this.stmt(`UPDATE tenants SET ${fields.join(', ')} WHERE id = ?`).run(vals)\n const row = this.stmt('SELECT * FROM tenants WHERE id = ?').get(id) as RawTenant | null\n if (!row) throw new Error(`Tenant ${id} not found`)\n return { id: row.id, name: row.name, slug: row.slug, createdAt: row.created_at, updatedAt: row.updated_at }\n }\n\n async deleteTenant(id: string): Promise<void> {\n this.stmt('DELETE FROM tenants WHERE id = ?').run(id)\n }\n\n async purgeExpiredConsents(olderThanDays: number): Promise<number> {\n const cutoff = new Date(Date.now() - olderThanDays * 86_400_000).toISOString()\n const toDelete = this.stmt(\n 'SELECT visitor_id FROM consent_records WHERE created_at < ?'\n ).all(cutoff) as unknown as { visitor_id: string }[]\n for (const { visitor_id } of toDelete) {\n this.stmt('DELETE FROM consent_history WHERE visitor_id = ?').run(visitor_id)\n this.stmt('DELETE FROM consent_records WHERE visitor_id = ?').run(visitor_id)\n }\n return toDelete.length\n }\n\n // ── API Keys ───────────────────────────────────────────────────────────────\n\n private mapApiKey(r: RawApiKey): ApiKey {\n return { id: r.id, tenantId: r.tenant_id, keyHash: r.key_hash, name: r.name, isActive: r.is_active === 1, createdAt: r.created_at }\n }\n\n async createApiKey(data: CreateApiKeyInput): Promise<ApiKey> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt('INSERT INTO api_keys (id,tenant_id,key_hash,name,created_at) VALUES (?,?,?,?,?)').run([id, data.tenantId, data.keyHash, data.name, now])\n const row = this.stmt('SELECT * FROM api_keys WHERE id = ?').get(id) as RawApiKey | null\n if (!row) throw new Error('Failed to create API key')\n return this.mapApiKey(row)\n }\n\n async getApiKeyByHash(keyHash: string): Promise<ApiKey | null> {\n const row = this.stmt('SELECT * FROM api_keys WHERE key_hash = ? AND is_active = 1').get(keyHash) as RawApiKey | null\n return row ? this.mapApiKey(row) : null\n }\n\n async revokeApiKey(id: string): Promise<void> {\n this.stmt('UPDATE api_keys SET is_active = 0 WHERE id = ?').run(id)\n }\n\n async getApiKeys(tenantId: string): Promise<ApiKey[]> {\n const rows = this.stmt('SELECT * FROM api_keys WHERE tenant_id = ? ORDER BY created_at DESC').all(tenantId) as unknown as RawApiKey[]\n return rows.map(r => this.mapApiKey(r))\n }\n\n // ── Cookie Templates ───────────────────────────────────────────────────────\n\n private mapCookieTemplate(r: RawCookieTemplate): ServerCookieTemplate {\n return { id: r.id, tenantId: r.tenant_id, name: r.name, cookies: JSON.parse(r.cookies_json), createdAt: r.created_at, updatedAt: r.updated_at }\n }\n\n async createCookieTemplate(data: CreateCookieTemplateInput): Promise<ServerCookieTemplate> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt('INSERT INTO cookie_templates (id,tenant_id,name,cookies_json,created_at,updated_at) VALUES (?,?,?,?,?,?)').run([id, data.tenantId, data.name, JSON.stringify(data.cookies), now, now])\n return this.mapCookieTemplate(this.stmt('SELECT * FROM cookie_templates WHERE id = ?').get(id) as unknown as RawCookieTemplate)\n }\n\n async updateCookieTemplate(id: string, data: UpdateCookieTemplateInput): Promise<ServerCookieTemplate> {\n const now = new Date().toISOString()\n if (data.name !== undefined) this.stmt('UPDATE cookie_templates SET name = ?, updated_at = ? WHERE id = ?').run([data.name, now, id])\n if (data.cookies !== undefined) this.stmt('UPDATE cookie_templates SET cookies_json = ?, updated_at = ? WHERE id = ?').run([JSON.stringify(data.cookies), now, id])\n const row = this.stmt('SELECT * FROM cookie_templates WHERE id = ?').get(id) as RawCookieTemplate | null\n if (!row) throw new Error('Cookie template not found')\n return this.mapCookieTemplate(row)\n }\n\n async deleteCookieTemplate(id: string): Promise<void> {\n this.stmt('DELETE FROM cookie_templates WHERE id = ?').run(id)\n }\n\n async getCookieTemplate(id: string): Promise<ServerCookieTemplate | null> {\n const row = this.stmt('SELECT * FROM cookie_templates WHERE id = ?').get(id) as RawCookieTemplate | null\n return row ? this.mapCookieTemplate(row) : null\n }\n\n async getCookieTemplates(tenantId: string): Promise<ServerCookieTemplate[]> {\n const rows = this.stmt('SELECT * FROM cookie_templates WHERE tenant_id = ? ORDER BY name ASC').all(tenantId) as unknown as RawCookieTemplate[]\n return rows.map(r => this.mapCookieTemplate(r))\n }\n\n async copyCookieTemplate(id: string, newName: string): Promise<ServerCookieTemplate> {\n const src = await this.getCookieTemplate(id)\n if (!src) throw new Error('Cookie template not found')\n return this.createCookieTemplate({ tenantId: src.tenantId, name: newName, cookies: src.cookies })\n }\n\n // ── UI Templates ───────────────────────────────────────────────────────────\n\n private mapUITemplate(r: RawUITemplate): ServerUITemplate {\n const s = JSON.parse(r.settings_json) as Omit<ServerUITemplate, 'id' | 'tenantId' | 'name' | 'createdAt' | 'updatedAt'>\n return { id: r.id, tenantId: r.tenant_id, name: r.name, ...s, createdAt: r.created_at, updatedAt: r.updated_at }\n }\n\n async createUITemplate(data: CreateUITemplateInput): Promise<ServerUITemplate> {\n const id = randomUUID()\n const now = new Date().toISOString()\n const { tenantId, name, ...settings } = data\n this.stmt('INSERT INTO ui_templates (id,tenant_id,name,settings_json,created_at,updated_at) VALUES (?,?,?,?,?,?)').run([id, tenantId, name, JSON.stringify(settings), now, now])\n return this.mapUITemplate(this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as unknown as RawUITemplate)\n }\n\n async updateUITemplate(id: string, data: UpdateUITemplateInput): Promise<ServerUITemplate> {\n const now = new Date().toISOString()\n const row = this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as RawUITemplate | null\n if (!row) throw new Error('UI template not found')\n if (data.name !== undefined) this.stmt('UPDATE ui_templates SET name = ?, updated_at = ? WHERE id = ?').run([data.name, now, id])\n const { name: _n, ...settingsUpdate } = data\n if (Object.keys(settingsUpdate).length > 0) {\n const current = JSON.parse(row.settings_json) as Record<string, unknown>\n const merged = { ...current, ...settingsUpdate }\n this.stmt('UPDATE ui_templates SET settings_json = ?, updated_at = ? WHERE id = ?').run([JSON.stringify(merged), now, id])\n }\n return this.mapUITemplate(this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as unknown as RawUITemplate)\n }\n\n async deleteUITemplate(id: string): Promise<void> {\n this.stmt('DELETE FROM ui_templates WHERE id = ?').run(id)\n }\n\n async getUITemplate(id: string): Promise<ServerUITemplate | null> {\n const row = this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as RawUITemplate | null\n return row ? this.mapUITemplate(row) : null\n }\n\n async getUITemplates(tenantId: string): Promise<ServerUITemplate[]> {\n const rows = this.stmt('SELECT * FROM ui_templates WHERE tenant_id = ? ORDER BY name ASC').all(tenantId) as unknown as RawUITemplate[]\n return rows.map(r => this.mapUITemplate(r))\n }\n\n async copyUITemplate(id: string, newName: string): Promise<ServerUITemplate> {\n const src = await this.getUITemplate(id)\n if (!src) throw new Error('UI template not found')\n const { tenantId, mainBanner, gpcBanner, preferenceModal } = src\n return this.createUITemplate({ tenantId, name: newName, mainBanner, gpcBanner, preferenceModal })\n }\n}\n","import type { DatabaseSync, StatementSync } from 'node:sqlite'\n\nconst MAX_PAGE_SIZE = 500\nimport { randomUUID, randomProfileId } from '../../utils/crypto'\nimport {\n SEED_SQL,\n SCHEMA_SQL_SQLITE,\n SCHEMA_SQL_SQLITE_API_KEYS,\n SCHEMA_SQL_SQLITE_ENTERPRISE,\n SCHEMA_SQL_SQLITE_TEMPLATES,\n} from '../seed-data'\nimport type {\n StorageAdapter,\n StorageConfig,\n Profile,\n ProfileConfig,\n CreateProfileInput,\n UpdateProfileInput,\n ConsentDbRecord,\n ConsentHistoryEntry,\n ConsentValue,\n CreateConsentInput,\n UpdateConsentInput,\n ConsentFilters,\n Visitor,\n VisitorFilters,\n CreateVisitorInput,\n UpdateVisitorInput,\n AdminUser,\n CreateUserInput,\n UpdateUserInput,\n Role,\n CreateRoleInput,\n UpdateRoleInput,\n Permission,\n AuditLog,\n AuditFilters,\n CreateAuditLogInput,\n OverviewStats,\n CategoryStats,\n TimelineEntry,\n CountryStat,\n GpcStats,\n Tenant,\n ApiKey,\n CreateApiKeyInput,\n CreateTenantInput,\n UpdateTenantInput,\n ServerCookieTemplate,\n ServerUITemplate,\n CreateCookieTemplateInput,\n UpdateCookieTemplateInput,\n CreateUITemplateInput,\n UpdateUITemplateInput,\n} from '@consenti/types'\n\ninterface RawProfile {\n id: string; tenant_id: string; name: string; default_locale: string\n version: number; profile_json: string\n created_at: string; updated_at: string\n}\ninterface RawConsent {\n id: string; tenant_id: string; visitor_id: string; profile_id: string\n profile_version: number; locale: string; consent_json: string\n gpc_detected: number; source: string; created_at: string; updated_at: string\n age_verified?: number; parental_consent_token?: string | null; tcf_string?: string | null\n}\ninterface RawConsentHistory {\n id: string; tenant_id: string; consent_record_id: string; visitor_id: string\n old_json: string | null; new_json: string; action: string; created_at: string\n}\ninterface RawVisitor {\n id: string; tenant_id: string; visitor_id: string\n country: string | null; region: string | null; city: string | null\n ip_hash: string | null; user_agent_hash: string | null\n first_seen: string; last_seen: string\n}\ninterface RawUser {\n id: string; tenant_id: string; name: string; email: string\n password_hash: string; is_active: number; created_at: string; updated_at: string\n totp_secret?: string | null; totp_enabled?: number\n}\ninterface RawRole {\n id: string; tenant_id: string; name: string; description: string | null\n}\ninterface RawPermission {\n id: string; name: string; description: string | null\n}\ninterface RawAuditLog {\n id: string; tenant_id: string; user_id: string | null; action: string\n resource_type: string; resource_id: string | null\n old_data: string | null; new_data: string | null; created_at: string\n}\ninterface RawTenant {\n id: string; name: string; slug: string; created_at: string; updated_at: string\n}\ninterface RawApiKey {\n id: string; tenant_id: string; key_hash: string; name: string; is_active: number; created_at: string\n}\ninterface RawCookieTemplate {\n id: string; tenant_id: string; name: string; cookies_json: string; created_at: string; updated_at: string\n}\ninterface RawUITemplate {\n id: string; tenant_id: string; name: string; settings_json: string; created_at: string; updated_at: string\n}\n\n\ntype Stmt = StatementSync\n\nexport class NodeSqliteBuiltinAdapter implements StorageAdapter {\n private db!: DatabaseSync\n private cache = new Map<string, Stmt>()\n\n constructor(private config: StorageConfig) {}\n\n private stmt(sql: string): Stmt {\n let s = this.cache.get(sql)\n if (!s) { s = this.db.prepare(sql); this.cache.set(sql, s) }\n return s\n }\n\n async connect(): Promise<void> {\n // Lazy: node:sqlite is only available on Node.js >= 22.5.0.\n // Loading it here (not at module load) prevents startup failure on Node 20.\n const { DatabaseSync: Db } = await import('node:sqlite').catch(() => {\n throw new Error(`driver 'node:sqlite' requires Node.js >= 22.5.0 (current: ${process.version})`)\n }) as { DatabaseSync: new(path: string) => DatabaseSync }\n this.db = new Db(this.config.path ?? './consenti.db')\n this.db.exec('PRAGMA journal_mode=WAL')\n this.db.exec('PRAGMA foreign_keys=ON')\n this.db.exec('PRAGMA synchronous=NORMAL')\n await this.migrate()\n }\n\n async disconnect(): Promise<void> {\n this.cache.clear()\n this.db.close()\n }\n\n async migrate(): Promise<void> {\n const row = this.db.prepare('PRAGMA user_version').get() as { user_version: number }\n if (row.user_version < 1) {\n this.db.exec(SCHEMA_SQL_SQLITE)\n this.db.exec(SEED_SQL)\n this.db.exec('PRAGMA user_version = 1')\n }\n if (row.user_version < 2) {\n this.db.exec(SCHEMA_SQL_SQLITE_API_KEYS)\n this.db.exec('PRAGMA user_version = 2')\n }\n if (row.user_version < 3) {\n this.db.exec(SCHEMA_SQL_SQLITE_ENTERPRISE)\n this.db.exec('PRAGMA user_version = 3')\n }\n if (row.user_version < 4) {\n this.db.exec('ALTER TABLE user_roles ADD COLUMN tenant_id TEXT NOT NULL DEFAULT \\'default\\'')\n this.db.exec('PRAGMA user_version = 4')\n }\n if (row.user_version < 5) {\n this.db.exec(SCHEMA_SQL_SQLITE_TEMPLATES)\n this.db.exec('PRAGMA user_version = 5')\n }\n }\n\n // ── Profiles ──────────────────────────────────────────────────────────────\n\n private mapProfile(row: RawProfile): Profile {\n return {\n id: row.id,\n tenantId: row.tenant_id,\n name: row.name,\n defaultLocale: row.default_locale,\n version: row.version,\n profileJson: JSON.parse(row.profile_json) as ProfileConfig,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }\n }\n\n async createProfile(data: CreateProfileInput): Promise<Profile> {\n const id = randomProfileId()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO profiles (id,tenant_id,name,default_locale,profile_json,created_at,updated_at) VALUES (?,?,?,?,?,?,?)'\n ).run(id, data.tenantId, data.name, data.defaultLocale, JSON.stringify(data.profileJson), now, now)\n const profile = await this.getProfile(id)\n if (!profile) throw new Error('Failed to create profile')\n return profile\n }\n\n async updateProfile(id: string, data: UpdateProfileInput): Promise<Profile> {\n const existing = await this.getProfile(id)\n if (!existing) throw new Error(`Profile ${id} not found`)\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?', 'version = version + 1']\n const vals: (string | number | null)[] = [now]\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.defaultLocale != null) { fields.push('default_locale = ?'); vals.push(data.defaultLocale) }\n if (data.profileJson != null) { fields.push('profile_json = ?'); vals.push(JSON.stringify(data.profileJson)) }\n vals.push(id)\n this.stmt(`UPDATE profiles SET ${fields.join(', ')} WHERE id = ?`).run(...vals)\n const updated = await this.getProfile(id)\n if (!updated) throw new Error('Failed to update profile')\n return updated\n }\n\n async deleteProfile(id: string): Promise<void> {\n this.stmt('DELETE FROM profiles WHERE id = ?').run(id)\n }\n\n async getProfile(id: string): Promise<Profile | null> {\n const row = this.stmt('SELECT * FROM profiles WHERE id = ?').get(id) as RawProfile | undefined\n return row ? this.mapProfile(row) : null\n }\n\n async getProfiles(tenantId: string): Promise<Profile[]> {\n const rows = this.stmt('SELECT * FROM profiles WHERE tenant_id = ? ORDER BY created_at ASC').all(tenantId) as unknown as RawProfile[]\n return rows.map(r => this.mapProfile(r))\n }\n\n // ── Consents ──────────────────────────────────────────────────────────────\n\n private mapConsent(row: RawConsent): ConsentDbRecord {\n return {\n id: row.id,\n tenantId: row.tenant_id,\n visitorId: row.visitor_id,\n profileId: row.profile_id,\n profileVersion: row.profile_version,\n locale: row.locale,\n consentJson: JSON.parse(row.consent_json) as ConsentValue,\n gpcDetected: row.gpc_detected === 1,\n source: row.source as ConsentDbRecord['source'],\n ...(row.age_verified != null && row.age_verified !== 0 ? { ageVerified: true } : {}),\n ...(row.parental_consent_token != null ? { parentalConsentToken: row.parental_consent_token } : {}),\n ...(row.tcf_string != null ? { tcfString: row.tcf_string } : {}),\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }\n }\n\n async createConsent(data: CreateConsentInput): Promise<ConsentDbRecord> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO consent_records (id,tenant_id,visitor_id,profile_id,profile_version,locale,consent_json,gpc_detected,source,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)'\n ).run(id, data.tenantId, data.visitorId, data.profileId, data.profileVersion, data.locale, JSON.stringify(data.consentJson), data.gpcDetected ? 1 : 0, data.source, now, now)\n const histId = randomUUID()\n this.stmt(\n 'INSERT INTO consent_history (id,tenant_id,consent_record_id,visitor_id,old_json,new_json,action,created_at) VALUES (?,?,?,?,?,?,?,?)'\n ).run(histId, data.tenantId, id, data.visitorId, null, JSON.stringify(data.consentJson), 'created', now)\n const record = await this.getConsent(data.visitorId)\n if (!record) throw new Error('Failed to create consent')\n return record\n }\n\n async updateConsent(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord> {\n const existing = await this.getConsent(visitorId)\n if (!existing) throw new Error(`Consent for visitor ${visitorId} not found`)\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?', 'consent_json = ?']\n const vals: (string | number | null)[] = [now, JSON.stringify(data.consentJson)]\n if (data.locale != null) { fields.push('locale = ?'); vals.push(data.locale) }\n if (data.gpcDetected != null) { fields.push('gpc_detected = ?'); vals.push(data.gpcDetected ? 1 : 0) }\n vals.push(visitorId)\n this.stmt(`UPDATE consent_records SET ${fields.join(', ')} WHERE visitor_id = ?`).run(...vals)\n const histId = randomUUID()\n this.stmt(\n 'INSERT INTO consent_history (id,tenant_id,consent_record_id,visitor_id,old_json,new_json,action,created_at) VALUES (?,?,?,?,?,?,?,?)'\n ).run(histId, existing.tenantId, existing.id, visitorId, JSON.stringify(existing.consentJson), JSON.stringify(data.consentJson), 'updated', now)\n const updated = await this.getConsent(visitorId)\n if (!updated) throw new Error('Failed to update consent')\n return updated\n }\n\n async deleteConsent(visitorId: string): Promise<void> {\n this.stmt('DELETE FROM consent_history WHERE visitor_id = ?').run(visitorId)\n this.stmt('DELETE FROM consent_records WHERE visitor_id = ?').run(visitorId)\n }\n\n async getConsent(visitorId: string): Promise<ConsentDbRecord | null> {\n const row = this.stmt('SELECT * FROM consent_records WHERE visitor_id = ?').get(visitorId) as RawConsent | undefined\n return row ? this.mapConsent(row) : null\n }\n\n async getConsents(filters: ConsentFilters): Promise<ConsentDbRecord[]> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: (string | number | null)[] = [filters.tenantId]\n if (filters.profileId) { conditions.push('profile_id = ?'); vals.push(filters.profileId) }\n if (filters.from) { conditions.push('created_at >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('created_at <= ?'); vals.push(filters.to) }\n const limit = Math.min(filters.limit ?? 50, MAX_PAGE_SIZE)\n const offset = ((filters.page ?? 1) - 1) * limit\n vals.push(limit, offset)\n const rows = this.stmt(\n `SELECT * FROM consent_records WHERE ${conditions.join(' AND ')} ORDER BY created_at DESC LIMIT ? OFFSET ?`\n ).all(...vals) as unknown as RawConsent[]\n return rows.map(r => this.mapConsent(r))\n }\n\n async *streamConsents(filters: ConsentFilters): AsyncIterable<ConsentDbRecord> {\n const pageSize = 500\n let offset = 0\n while (true) {\n const rows = this.stmt(\n 'SELECT * FROM consent_records WHERE tenant_id = ? LIMIT ? OFFSET ?'\n ).all(filters.tenantId, pageSize, offset) as unknown as RawConsent[]\n if (rows.length === 0) break\n for (const row of rows) yield this.mapConsent(row)\n offset += pageSize\n }\n }\n\n async getConsentHistory(visitorId: string): Promise<ConsentHistoryEntry[]> {\n const rows = this.stmt(\n 'SELECT * FROM consent_history WHERE visitor_id = ? ORDER BY created_at ASC'\n ).all(visitorId) as unknown as RawConsentHistory[]\n return rows.map(r => ({\n id: r.id,\n tenantId: r.tenant_id,\n consentRecordId: r.consent_record_id,\n visitorId: r.visitor_id,\n oldJson: r.old_json != null ? JSON.parse(r.old_json) as ConsentValue : null,\n newJson: JSON.parse(r.new_json) as ConsentValue,\n action: r.action as ConsentHistoryEntry['action'],\n createdAt: r.created_at,\n }))\n }\n\n // ── Visitors ──────────────────────────────────────────────────────────────\n\n private mapVisitor(row: RawVisitor): Visitor {\n return {\n id: row.id,\n tenantId: row.tenant_id,\n visitorId: row.visitor_id,\n firstSeen: row.first_seen,\n lastSeen: row.last_seen,\n ...(row.country != null ? { country: row.country } : {}),\n ...(row.region != null ? { region: row.region } : {}),\n ...(row.city != null ? { city: row.city } : {}),\n ...(row.ip_hash != null ? { ipHash: row.ip_hash } : {}),\n ...(row.user_agent_hash != null ? { userAgentHash: row.user_agent_hash } : {}),\n }\n }\n\n async createVisitor(data: CreateVisitorInput): Promise<Visitor> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO visitors (id,tenant_id,visitor_id,country,region,city,ip_hash,user_agent_hash,first_seen,last_seen) VALUES (?,?,?,?,?,?,?,?,?,?)'\n ).run(id, data.tenantId, data.visitorId, data.country ?? null, data.region ?? null, data.city ?? null, data.ipHash ?? null, data.userAgentHash ?? null, now, now)\n const visitor = await this.getVisitor(data.visitorId)\n if (!visitor) throw new Error('Failed to create visitor')\n return visitor\n }\n\n async updateVisitor(visitorId: string, data: UpdateVisitorInput): Promise<Visitor> {\n const now = new Date().toISOString()\n const fields: string[] = ['last_seen = ?']\n const vals: (string | number | null)[] = [data.lastSeen ?? now]\n if (data.country != null) { fields.push('country = ?'); vals.push(data.country) }\n if (data.region != null) { fields.push('region = ?'); vals.push(data.region) }\n if (data.city != null) { fields.push('city = ?'); vals.push(data.city) }\n vals.push(visitorId)\n this.stmt(`UPDATE visitors SET ${fields.join(', ')} WHERE visitor_id = ?`).run(...vals)\n const visitor = await this.getVisitor(visitorId)\n if (!visitor) throw new Error(`Visitor ${visitorId} not found`)\n return visitor\n }\n\n async deleteVisitor(visitorId: string): Promise<void> {\n this.stmt('DELETE FROM visitors WHERE visitor_id = ?').run(visitorId)\n }\n\n async getVisitor(visitorId: string): Promise<Visitor | null> {\n const row = this.stmt('SELECT * FROM visitors WHERE visitor_id = ?').get(visitorId) as RawVisitor | undefined\n return row ? this.mapVisitor(row) : null\n }\n\n async getVisitors(filters: VisitorFilters): Promise<Visitor[]> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: (string | number | null)[] = [filters.tenantId]\n if (filters.from) { conditions.push('first_seen >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('first_seen <= ?'); vals.push(filters.to) }\n const limit = Math.min(filters.limit ?? 50, MAX_PAGE_SIZE)\n const offset = ((filters.page ?? 1) - 1) * limit\n vals.push(limit, offset)\n const rows = this.stmt(\n `SELECT * FROM visitors WHERE ${conditions.join(' AND ')} ORDER BY last_seen DESC LIMIT ? OFFSET ?`\n ).all(...vals) as unknown as RawVisitor[]\n return rows.map(r => this.mapVisitor(r))\n }\n\n // ── Users ─────────────────────────────────────────────────────────────────\n\n private mapUser(row: RawUser): AdminUser {\n return {\n id: row.id,\n tenantId: row.tenant_id,\n name: row.name,\n email: row.email,\n passwordHash: row.password_hash,\n isActive: row.is_active === 1,\n totpEnabled: row.totp_enabled === 1,\n ...(row.totp_secret != null ? { totpSecret: row.totp_secret } : {}),\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }\n }\n\n async createUser(data: CreateUserInput): Promise<AdminUser> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO users (id,tenant_id,name,email,password_hash,created_at,updated_at) VALUES (?,?,?,?,?,?,?)'\n ).run(id, data.tenantId, data.name, data.email, data.passwordHash, now, now)\n const user = await this.getUserByEmail(data.email)\n if (!user) throw new Error('Failed to create user')\n return user\n }\n\n async updateUser(id: string, data: UpdateUserInput): Promise<AdminUser> {\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?']\n const vals: (string | number | null)[] = [now]\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.email != null) { fields.push('email = ?'); vals.push(data.email) }\n if (data.passwordHash != null) { fields.push('password_hash = ?'); vals.push(data.passwordHash) }\n if (data.isActive != null) { fields.push('is_active = ?'); vals.push(data.isActive ? 1 : 0) }\n if ('totpSecret' in data) { fields.push('totp_secret = ?'); vals.push(data.totpSecret ?? null) }\n if (data.totpEnabled != null) { fields.push('totp_enabled = ?'); vals.push(data.totpEnabled ? 1 : 0) }\n vals.push(id)\n this.stmt(`UPDATE users SET ${fields.join(', ')} WHERE id = ?`).run(...vals)\n const row = this.stmt('SELECT * FROM users WHERE id = ?').get(id) as RawUser | undefined\n if (!row) throw new Error(`User ${id} not found`)\n return this.mapUser(row)\n }\n\n async deleteUser(id: string): Promise<void> {\n this.stmt('DELETE FROM user_roles WHERE user_id = ?').run(id)\n this.stmt('DELETE FROM users WHERE id = ?').run(id)\n }\n\n async getUserById(id: string): Promise<AdminUser | null> {\n const row = this.stmt('SELECT * FROM users WHERE id = ?').get(id) as RawUser | undefined\n return row ? this.mapUser(row) : null\n }\n\n async getUserByEmail(email: string): Promise<AdminUser | null> {\n const row = this.stmt('SELECT * FROM users WHERE email = ?').get(email) as RawUser | undefined\n return row ? this.mapUser(row) : null\n }\n\n async getUsers(tenantId: string): Promise<AdminUser[]> {\n const rows = this.stmt('SELECT * FROM users WHERE tenant_id = ? ORDER BY created_at ASC').all(tenantId) as unknown as RawUser[]\n return rows.map(r => this.mapUser(r))\n }\n\n async countUsers(tenantId?: string): Promise<number> {\n const row = tenantId\n ? this.stmt('SELECT COUNT(*) as n FROM users WHERE tenant_id = ?').get(tenantId) as { n: number } | undefined\n : this.stmt('SELECT COUNT(*) as n FROM users').get() as { n: number } | undefined\n return row?.n ?? 0\n }\n\n // ── Roles & Permissions ───────────────────────────────────────────────────\n\n async getRoles(tenantId: string): Promise<Role[]> {\n const rows = this.stmt('SELECT * FROM roles WHERE tenant_id = ?').all(tenantId) as unknown as RawRole[]\n return rows.map(r => ({\n id: r.id, tenantId: r.tenant_id, name: r.name,\n ...(r.description != null ? { description: r.description } : {}),\n }))\n }\n\n async createRole(data: CreateRoleInput): Promise<Role> {\n const id = randomUUID()\n this.stmt('INSERT INTO roles (id,tenant_id,name,description) VALUES (?,?,?,?)').run(\n id, data.tenantId, data.name, data.description ?? null\n )\n const row = this.stmt('SELECT * FROM roles WHERE id = ?').get(id) as RawRole | undefined\n if (!row) throw new Error('Failed to create role')\n return { id: row.id, tenantId: row.tenant_id, name: row.name, ...(row.description != null ? { description: row.description } : {}) }\n }\n\n async updateRole(id: string, data: UpdateRoleInput): Promise<Role> {\n const fields: string[] = []\n const vals: (string | number | null)[] = []\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.description != null) { fields.push('description = ?'); vals.push(data.description) }\n if (fields.length > 0) {\n vals.push(id)\n this.stmt(`UPDATE roles SET ${fields.join(', ')} WHERE id = ?`).run(...vals)\n }\n const row = this.stmt('SELECT * FROM roles WHERE id = ?').get(id) as RawRole | undefined\n if (!row) throw new Error(`Role ${id} not found`)\n return { id: row.id, tenantId: row.tenant_id, name: row.name, ...(row.description != null ? { description: row.description } : {}) }\n }\n\n async deleteRole(id: string): Promise<void> {\n this.stmt('DELETE FROM role_permissions WHERE role_id = ?').run(id)\n this.stmt('DELETE FROM user_roles WHERE role_id = ?').run(id)\n this.stmt('DELETE FROM roles WHERE id = ?').run(id)\n }\n\n async getAllPermissions(): Promise<Permission[]> {\n const rows = this.stmt('SELECT * FROM permissions ORDER BY name ASC').all() as unknown as RawPermission[]\n return rows.map(r => ({ id: r.id, name: r.name, ...(r.description != null ? { description: r.description } : {}) }))\n }\n\n async assignPermissionToRole(roleId: string, permissionId: string): Promise<void> {\n this.stmt('INSERT OR IGNORE INTO role_permissions (role_id,permission_id) VALUES (?,?)').run(roleId, permissionId)\n }\n\n async revokePermissionFromRole(roleId: string, permissionId: string): Promise<void> {\n this.stmt('DELETE FROM role_permissions WHERE role_id = ? AND permission_id = ?').run(roleId, permissionId)\n }\n\n async getPermissionsForRole(roleId: string): Promise<Permission[]> {\n const rows = this.stmt(\n 'SELECT p.* FROM permissions p JOIN role_permissions rp ON rp.permission_id = p.id WHERE rp.role_id = ?'\n ).all(roleId) as unknown as RawPermission[]\n return rows.map(r => ({\n id: r.id, name: r.name,\n ...(r.description != null ? { description: r.description } : {}),\n }))\n }\n\n async getUserRoles(userId: string, tenantId?: string): Promise<Role[]> {\n const rows = tenantId\n ? this.stmt(\n 'SELECT r.* FROM roles r JOIN user_roles ur ON ur.role_id = r.id WHERE ur.user_id = ? AND ur.tenant_id = ?'\n ).all(userId, tenantId) as unknown as RawRole[]\n : this.stmt(\n 'SELECT r.* FROM roles r JOIN user_roles ur ON ur.role_id = r.id WHERE ur.user_id = ?'\n ).all(userId) as unknown as RawRole[]\n return rows.map(r => ({\n id: r.id, tenantId: r.tenant_id, name: r.name,\n ...(r.description != null ? { description: r.description } : {}),\n }))\n }\n\n async assignRole(userId: string, roleId: string, tenantId = 'default'): Promise<void> {\n this.stmt('INSERT OR IGNORE INTO user_roles (user_id, role_id, tenant_id) VALUES (?,?,?)').run(userId, roleId, tenantId)\n }\n\n async revokeRole(userId: string, roleId: string, tenantId?: string): Promise<void> {\n if (tenantId) {\n this.stmt('DELETE FROM user_roles WHERE user_id = ? AND role_id = ? AND tenant_id = ?').run(userId, roleId, tenantId)\n } else {\n this.stmt('DELETE FROM user_roles WHERE user_id = ? AND role_id = ?').run(userId, roleId)\n }\n }\n\n // ── Audit ─────────────────────────────────────────────────────────────────\n\n async createLog(data: CreateAuditLogInput): Promise<void> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO audit_logs (id,tenant_id,user_id,action,resource_type,resource_id,old_data,new_data,created_at) VALUES (?,?,?,?,?,?,?,?,?)'\n ).run(\n id, data.tenantId, data.userId ?? null, data.action, data.resourceType,\n data.resourceId ?? null,\n data.oldData != null ? JSON.stringify(data.oldData) : null,\n data.newData != null ? JSON.stringify(data.newData) : null,\n now\n )\n }\n\n async getLogs(filters: AuditFilters): Promise<AuditLog[]> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: (string | number | null)[] = [filters.tenantId]\n if (filters.action) { conditions.push('action = ?'); vals.push(filters.action) }\n if (filters.resourceType) { conditions.push('resource_type = ?'); vals.push(filters.resourceType) }\n if (filters.from) { conditions.push('created_at >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('created_at <= ?'); vals.push(filters.to) }\n const limit = Math.min(filters.limit ?? 50, MAX_PAGE_SIZE)\n const offset = ((filters.page ?? 1) - 1) * limit\n vals.push(limit, offset)\n const rows = this.stmt(\n `SELECT * FROM audit_logs WHERE ${conditions.join(' AND ')} ORDER BY created_at DESC LIMIT ? OFFSET ?`\n ).all(...vals) as unknown as RawAuditLog[]\n return rows.map(r => this.mapAuditLog(r))\n }\n\n private mapAuditLog(r: RawAuditLog): AuditLog {\n return {\n id: r.id, tenantId: r.tenant_id, action: r.action,\n resourceType: r.resource_type, createdAt: r.created_at,\n ...(r.user_id != null ? { userId: r.user_id } : {}),\n ...(r.resource_id != null ? { resourceId: r.resource_id } : {}),\n ...(r.old_data != null ? { oldData: JSON.parse(r.old_data) as unknown } : {}),\n ...(r.new_data != null ? { newData: JSON.parse(r.new_data) as unknown } : {}),\n }\n }\n\n async *streamAuditLogs(filters: AuditFilters): AsyncIterable<AuditLog> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: (string | number | null)[] = [filters.tenantId]\n if (filters.action) { conditions.push('action = ?'); vals.push(filters.action) }\n if (filters.from) { conditions.push('created_at >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('created_at <= ?'); vals.push(filters.to) }\n const pageSize = 500\n let offset = 0\n while (true) {\n const rows = this.stmt(\n `SELECT * FROM audit_logs WHERE ${conditions.join(' AND ')} ORDER BY created_at DESC LIMIT ? OFFSET ?`\n ).all(...vals, pageSize, offset) as unknown as RawAuditLog[]\n if (rows.length === 0) break\n for (const row of rows) yield this.mapAuditLog(row)\n offset += pageSize\n }\n }\n\n // ── Stats ──────────────────────────────────────────────────────────────────\n\n async getOverviewStats(tenantId: string): Promise<OverviewStats> {\n const tc = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ?').get(tenantId) as { n: number } | undefined\n const gc = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ? AND gpc_detected = 1').get(tenantId) as { n: number } | undefined\n const vc = this.stmt('SELECT COUNT(*) as n FROM visitors WHERE tenant_id = ?').get(tenantId) as { n: number } | undefined\n const totalConsents = tc?.n ?? 0\n\n const recent = this.stmt(\n 'SELECT consent_json FROM consent_records WHERE tenant_id = ? ORDER BY created_at DESC LIMIT 500'\n ).all(tenantId) as unknown as { consent_json: string }[]\n\n let accepted = 0, rejected = 0\n for (const r of recent) {\n const vals = Object.values(JSON.parse(r.consent_json) as Record<string, string>)\n const grantedPct = vals.length > 0 ? vals.filter(v => v === 'granted').length / vals.length : 0\n if (grantedPct >= 0.8) accepted++\n else if (grantedPct <= 0.2) rejected++\n }\n const sample = recent.length || 1\n\n return {\n totalConsents,\n gpcDetectedCount: gc?.n ?? 0,\n totalVisitors: vc?.n ?? 0,\n acceptedPct: Math.round((accepted / sample) * 100),\n rejectedPct: Math.round((rejected / sample) * 100),\n }\n }\n\n async getCategoryStats(tenantId: string): Promise<CategoryStats> {\n const rows = this.stmt(\n 'SELECT consent_json FROM consent_records WHERE tenant_id = ? LIMIT 5000'\n ).all(tenantId) as unknown as { consent_json: string }[]\n const stats: CategoryStats = {}\n for (const row of rows) {\n const consent = JSON.parse(row.consent_json) as Record<string, string>\n for (const [key, status] of Object.entries(consent)) {\n if (!stats[key]) stats[key] = { granted: 0, denied: 0, objected: 0 }\n if (status === 'granted') stats[key]!.granted++\n else if (status === 'denied') stats[key]!.denied++\n else if (status === 'objected') stats[key]!.objected++\n }\n }\n return stats\n }\n\n async getTimeline(tenantId: string, days = 30): Promise<TimelineEntry[]> {\n const rows = this.stmt(\n `SELECT date(created_at) as date, COUNT(*) as count FROM consent_records WHERE tenant_id = ? AND created_at >= date('now', ?) GROUP BY date(created_at) ORDER BY date ASC`\n ).all(tenantId, `-${days} days`) as unknown as { date: string; count: number }[]\n return rows.map(r => ({ date: r.date, count: r.count }))\n }\n\n async getCountries(tenantId: string): Promise<CountryStat[]> {\n const rows = this.stmt(\n `SELECT v.country, COUNT(*) as count FROM consent_records cr JOIN visitors v ON v.visitor_id = cr.visitor_id WHERE cr.tenant_id = ? AND v.country IS NOT NULL GROUP BY v.country ORDER BY count DESC LIMIT 50`\n ).all(tenantId) as unknown as { country: string; count: number }[]\n return rows.map(r => ({ country: r.country, count: r.count }))\n }\n\n async getGpcStats(tenantId: string): Promise<GpcStats> {\n const total = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ?').get(tenantId) as { n: number } | undefined\n const detected = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ? AND gpc_detected = 1').get(tenantId) as { n: number } | undefined\n const t = total?.n ?? 0\n const d = detected?.n ?? 0\n return { detected: d, total: t, rate: t > 0 ? Math.round((d / t) * 100) : 0 }\n }\n\n // ── Tenants ────────────────────────────────────────────────────────────────\n\n async getTenants(): Promise<Tenant[]> {\n const rows = this.stmt('SELECT * FROM tenants ORDER BY name ASC').all() as unknown as RawTenant[]\n return rows.map(r => ({ id: r.id, name: r.name, slug: r.slug, createdAt: r.created_at, updatedAt: r.updated_at }))\n }\n\n async createTenant(data: CreateTenantInput): Promise<Tenant> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt('INSERT INTO tenants (id,name,slug,created_at,updated_at) VALUES (?,?,?,?,?)').run(id, data.name, data.slug, now, now)\n const row = this.stmt('SELECT * FROM tenants WHERE id = ?').get(id) as RawTenant | undefined\n if (!row) throw new Error('Failed to create tenant')\n return { id: row.id, name: row.name, slug: row.slug, createdAt: row.created_at, updatedAt: row.updated_at }\n }\n\n async updateTenant(id: string, data: UpdateTenantInput): Promise<Tenant> {\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?']\n const vals: (string | number)[] = [now]\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.slug != null) { fields.push('slug = ?'); vals.push(data.slug) }\n vals.push(id)\n this.stmt(`UPDATE tenants SET ${fields.join(', ')} WHERE id = ?`).run(...vals)\n const row = this.stmt('SELECT * FROM tenants WHERE id = ?').get(id) as RawTenant | undefined\n if (!row) throw new Error(`Tenant ${id} not found`)\n return { id: row.id, name: row.name, slug: row.slug, createdAt: row.created_at, updatedAt: row.updated_at }\n }\n\n async deleteTenant(id: string): Promise<void> {\n this.stmt('DELETE FROM tenants WHERE id = ?').run(id)\n }\n\n async purgeExpiredConsents(olderThanDays: number): Promise<number> {\n const cutoff = new Date(Date.now() - olderThanDays * 86_400_000).toISOString()\n const toDelete = this.stmt(\n 'SELECT visitor_id FROM consent_records WHERE created_at < ?'\n ).all(cutoff) as unknown as { visitor_id: string }[]\n for (const { visitor_id } of toDelete) {\n this.stmt('DELETE FROM consent_history WHERE visitor_id = ?').run(visitor_id)\n this.stmt('DELETE FROM consent_records WHERE visitor_id = ?').run(visitor_id)\n }\n return toDelete.length\n }\n\n // ── API Keys ───────────────────────────────────────────────────────────────\n\n private mapApiKey(r: RawApiKey): ApiKey {\n return { id: r.id, tenantId: r.tenant_id, keyHash: r.key_hash, name: r.name, isActive: r.is_active === 1, createdAt: r.created_at }\n }\n\n async createApiKey(data: CreateApiKeyInput): Promise<ApiKey> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt('INSERT INTO api_keys (id,tenant_id,key_hash,name,created_at) VALUES (?,?,?,?,?)').run(id, data.tenantId, data.keyHash, data.name, now)\n const row = this.stmt('SELECT * FROM api_keys WHERE id = ?').get(id) as RawApiKey | undefined\n if (!row) throw new Error('Failed to create API key')\n return this.mapApiKey(row)\n }\n\n async getApiKeyByHash(keyHash: string): Promise<ApiKey | null> {\n const row = this.stmt('SELECT * FROM api_keys WHERE key_hash = ? AND is_active = 1').get(keyHash) as RawApiKey | undefined\n return row ? this.mapApiKey(row) : null\n }\n\n async revokeApiKey(id: string): Promise<void> {\n this.stmt('UPDATE api_keys SET is_active = 0 WHERE id = ?').run(id)\n }\n\n async getApiKeys(tenantId: string): Promise<ApiKey[]> {\n const rows = this.stmt('SELECT * FROM api_keys WHERE tenant_id = ? ORDER BY created_at DESC').all(tenantId) as unknown as RawApiKey[]\n return rows.map(r => this.mapApiKey(r))\n }\n\n // ── Cookie Templates ───────────────────────────────────────────────────────\n\n private mapCookieTemplate(r: RawCookieTemplate): ServerCookieTemplate {\n return { id: r.id, tenantId: r.tenant_id, name: r.name, cookies: JSON.parse(r.cookies_json), createdAt: r.created_at, updatedAt: r.updated_at }\n }\n\n async createCookieTemplate(data: CreateCookieTemplateInput): Promise<ServerCookieTemplate> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt('INSERT INTO cookie_templates (id,tenant_id,name,cookies_json,created_at,updated_at) VALUES (?,?,?,?,?,?)').run(id, data.tenantId, data.name, JSON.stringify(data.cookies), now, now)\n return this.mapCookieTemplate(this.stmt('SELECT * FROM cookie_templates WHERE id = ?').get(id) as unknown as RawCookieTemplate)\n }\n\n async updateCookieTemplate(id: string, data: UpdateCookieTemplateInput): Promise<ServerCookieTemplate> {\n const now = new Date().toISOString()\n if (data.name !== undefined) this.stmt('UPDATE cookie_templates SET name = ?, updated_at = ? WHERE id = ?').run(data.name, now, id)\n if (data.cookies !== undefined) this.stmt('UPDATE cookie_templates SET cookies_json = ?, updated_at = ? WHERE id = ?').run(JSON.stringify(data.cookies), now, id)\n const row = this.stmt('SELECT * FROM cookie_templates WHERE id = ?').get(id) as RawCookieTemplate | undefined\n if (!row) throw new Error('Cookie template not found')\n return this.mapCookieTemplate(row)\n }\n\n async deleteCookieTemplate(id: string): Promise<void> {\n this.stmt('DELETE FROM cookie_templates WHERE id = ?').run(id)\n }\n\n async getCookieTemplate(id: string): Promise<ServerCookieTemplate | null> {\n const row = this.stmt('SELECT * FROM cookie_templates WHERE id = ?').get(id) as RawCookieTemplate | undefined\n return row ? this.mapCookieTemplate(row) : null\n }\n\n async getCookieTemplates(tenantId: string): Promise<ServerCookieTemplate[]> {\n const rows = this.stmt('SELECT * FROM cookie_templates WHERE tenant_id = ? ORDER BY name ASC').all(tenantId) as unknown as RawCookieTemplate[]\n return rows.map(r => this.mapCookieTemplate(r))\n }\n\n async copyCookieTemplate(id: string, newName: string): Promise<ServerCookieTemplate> {\n const src = await this.getCookieTemplate(id)\n if (!src) throw new Error('Cookie template not found')\n return this.createCookieTemplate({ tenantId: src.tenantId, name: newName, cookies: src.cookies })\n }\n\n // ── UI Templates ───────────────────────────────────────────────────────────\n\n private mapUITemplate(r: RawUITemplate): ServerUITemplate {\n const s = JSON.parse(r.settings_json) as Omit<ServerUITemplate, 'id' | 'tenantId' | 'name' | 'createdAt' | 'updatedAt'>\n return { id: r.id, tenantId: r.tenant_id, name: r.name, ...s, createdAt: r.created_at, updatedAt: r.updated_at }\n }\n\n async createUITemplate(data: CreateUITemplateInput): Promise<ServerUITemplate> {\n const id = randomUUID()\n const now = new Date().toISOString()\n const { tenantId, name, ...settings } = data\n this.stmt('INSERT INTO ui_templates (id,tenant_id,name,settings_json,created_at,updated_at) VALUES (?,?,?,?,?,?)').run(id, tenantId, name, JSON.stringify(settings), now, now)\n return this.mapUITemplate(this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as unknown as RawUITemplate)\n }\n\n async updateUITemplate(id: string, data: UpdateUITemplateInput): Promise<ServerUITemplate> {\n const now = new Date().toISOString()\n const row = this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as RawUITemplate | undefined\n if (!row) throw new Error('UI template not found')\n if (data.name !== undefined) this.stmt('UPDATE ui_templates SET name = ?, updated_at = ? WHERE id = ?').run(data.name, now, id)\n const { name: _n, ...settingsUpdate } = data\n if (Object.keys(settingsUpdate).length > 0) {\n const current = JSON.parse(row.settings_json) as Record<string, unknown>\n const merged = { ...current, ...settingsUpdate }\n this.stmt('UPDATE ui_templates SET settings_json = ?, updated_at = ? WHERE id = ?').run(JSON.stringify(merged), now, id)\n }\n return this.mapUITemplate(this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as unknown as RawUITemplate)\n }\n\n async deleteUITemplate(id: string): Promise<void> {\n this.stmt('DELETE FROM ui_templates WHERE id = ?').run(id)\n }\n\n async getUITemplate(id: string): Promise<ServerUITemplate | null> {\n const row = this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as RawUITemplate | undefined\n return row ? this.mapUITemplate(row) : null\n }\n\n async getUITemplates(tenantId: string): Promise<ServerUITemplate[]> {\n const rows = this.stmt('SELECT * FROM ui_templates WHERE tenant_id = ? ORDER BY name ASC').all(tenantId) as unknown as RawUITemplate[]\n return rows.map(r => this.mapUITemplate(r))\n }\n\n async copyUITemplate(id: string, newName: string): Promise<ServerUITemplate> {\n const src = await this.getUITemplate(id)\n if (!src) throw new Error('UI template not found')\n const { tenantId, mainBanner, gpcBanner, preferenceModal } = src\n return this.createUITemplate({ tenantId, name: newName, mainBanner, gpcBanner, preferenceModal })\n }\n}\n","import type { MongoClient, Db } from 'mongodb'\nimport { randomUUID } from '../../utils/crypto'\nimport { SEED_TENANT, SEED_PERMISSIONS, SEED_ROLES, SEED_ROLE_PERMISSIONS } from '../seed-data'\nimport type {\n StorageAdapter, StorageConfig, Profile, ProfileConfig,\n CreateProfileInput, UpdateProfileInput,\n ConsentDbRecord, ConsentHistoryEntry, ConsentValue, ConsentFilters,\n CreateConsentInput, UpdateConsentInput,\n Visitor, VisitorFilters, CreateVisitorInput, UpdateVisitorInput,\n AdminUser, CreateUserInput, UpdateUserInput,\n Role, CreateRoleInput, UpdateRoleInput,\n Permission, AuditLog, AuditFilters, CreateAuditLogInput,\n OverviewStats, CategoryStats, TimelineEntry,\n CountryStat, GpcStats, Tenant, ApiKey, CreateApiKeyInput,\n CreateTenantInput, UpdateTenantInput,\n} from '@consenti/types'\n\n// ── Raw document shapes ────────────────────────────────────────────────────────\n\ninterface DocProfile {\n _id: string; tenant_id: string; name: string; default_locale: string\n version: number; profile_json: ProfileConfig\n created_at: string; updated_at: string\n}\ninterface DocConsent {\n _id: string; tenant_id: string; visitor_id: string; profile_id: string\n profile_version: number; locale: string; consent_json: ConsentValue\n gpc_detected: boolean; source: string; created_at: string; updated_at: string\n}\ninterface DocConsentHistory {\n _id: string; tenant_id: string; consent_record_id: string; visitor_id: string\n old_json: ConsentValue | null; new_json: ConsentValue; action: string; created_at: string\n}\ninterface DocVisitor {\n _id: string; tenant_id: string; visitor_id: string\n country?: string; region?: string; city?: string\n ip_hash?: string; user_agent_hash?: string\n first_seen: string; last_seen: string\n}\ninterface DocUser {\n _id: string; tenant_id: string; name: string; email: string\n password_hash: string; is_active: boolean; created_at: string; updated_at: string\n}\ninterface DocRole { _id: string; tenant_id: string; name: string; description?: string }\ninterface DocPermission { _id: string; name: string; description?: string }\ninterface DocUserRole { user_id: string; role_id: string; tenant_id?: string }\ninterface DocRolePermission { role_id: string; permission_id: string }\ninterface DocAuditLog {\n _id: string; tenant_id: string; user_id?: string; action: string\n resource_type: string; resource_id?: string\n old_data?: unknown; new_data?: unknown; created_at: string\n}\ninterface DocApiKey {\n _id: string; tenant_id: string; key_hash: string; name: string; is_active: boolean; created_at: string\n}\n\n// ── Mapper helpers ─────────────────────────────────────────────────────────────\n\nfunction cast<T extends object>(doc: object | null): T | null {\n return doc as T | null\n}\n\nfunction castArr<T extends object>(docs: object[]): T[] {\n return docs as T[]\n}\n\nfunction mapProfile(d: DocProfile): Profile {\n return {\n id: d._id, tenantId: d.tenant_id, name: d.name,\n defaultLocale: d.default_locale, version: d.version,\n profileJson: d.profile_json, createdAt: d.created_at, updatedAt: d.updated_at,\n }\n}\n\nfunction mapConsent(d: DocConsent): ConsentDbRecord {\n return {\n id: d._id, tenantId: d.tenant_id, visitorId: d.visitor_id, profileId: d.profile_id,\n profileVersion: d.profile_version, locale: d.locale, consentJson: d.consent_json,\n gpcDetected: d.gpc_detected, source: d.source as ConsentDbRecord['source'],\n createdAt: d.created_at, updatedAt: d.updated_at,\n }\n}\n\nfunction mapHistory(d: DocConsentHistory): ConsentHistoryEntry {\n return {\n id: d._id, tenantId: d.tenant_id, consentRecordId: d.consent_record_id,\n visitorId: d.visitor_id, oldJson: d.old_json, newJson: d.new_json,\n action: d.action as ConsentHistoryEntry['action'], createdAt: d.created_at,\n }\n}\n\nfunction mapVisitor(d: DocVisitor): Visitor {\n return {\n id: d._id, tenantId: d.tenant_id, visitorId: d.visitor_id,\n ...(d.country != null ? { country: d.country } : {}),\n ...(d.region != null ? { region: d.region } : {}),\n ...(d.city != null ? { city: d.city } : {}),\n ...(d.ip_hash != null ? { ipHash: d.ip_hash } : {}),\n ...(d.user_agent_hash!= null ? { userAgentHash: d.user_agent_hash} : {}),\n firstSeen: d.first_seen, lastSeen: d.last_seen,\n }\n}\n\nfunction mapUser(d: DocUser): AdminUser {\n return {\n id: d._id, tenantId: d.tenant_id, name: d.name, email: d.email,\n passwordHash: d.password_hash, isActive: d.is_active,\n createdAt: d.created_at, updatedAt: d.updated_at,\n }\n}\n\nfunction mapRole(d: DocRole): Role {\n return {\n id: d._id, tenantId: d.tenant_id, name: d.name,\n ...(d.description != null ? { description: d.description } : {}),\n }\n}\n\nfunction mapPermission(d: DocPermission): Permission {\n return {\n id: d._id, name: d.name,\n ...(d.description != null ? { description: d.description } : {}),\n }\n}\n\nfunction mapAuditLog(d: DocAuditLog): AuditLog {\n return {\n id: d._id, tenantId: d.tenant_id, action: d.action, resourceType: d.resource_type,\n ...(d.user_id != null ? { userId: d.user_id } : {}),\n ...(d.resource_id != null ? { resourceId: d.resource_id } : {}),\n ...(d.old_data != null ? { oldData: d.old_data } : {}),\n ...(d.new_data != null ? { newData: d.new_data } : {}),\n createdAt: d.created_at,\n }\n}\n\n// ── Adapter ────────────────────────────────────────────────────────────────────\n\n// Custom thin wrappers so MongoDB's ObjectId generics don't interfere with our string _id.\n// DocCursor extends AsyncIterable so it supports `for await...of` iteration.\ninterface DocCursor extends AsyncIterable<object> {\n sort(s: object): DocCursor\n skip(n: number): DocCursor\n limit(n: number): DocCursor\n toArray(): Promise<object[]>\n}\ninterface DocCollection {\n insertOne(doc: object): Promise<object>\n findOne(filter: object): Promise<object | null>\n findOneAndUpdate(filter: object, update: object, options?: object): Promise<object | null>\n find(filter: object): DocCursor\n updateOne(filter: object, update: object, options?: object): Promise<object>\n deleteOne(filter: object): Promise<object>\n deleteMany(filter: object): Promise<object>\n countDocuments(filter?: object): Promise<number>\n createIndex(spec: object, options?: object): Promise<object>\n aggregate(pipeline: object[]): { toArray(): Promise<object[]> }\n}\n\nexport class MongoDBAdapter implements StorageAdapter {\n private client!: MongoClient\n private db!: Db\n\n constructor(private config: StorageConfig) {}\n\n private col(name: string): DocCollection {\n // MongoDB's Collection generics assume ObjectId for _id; we use string UUIDs throughout.\n // The cast via unknown is the TypeScript-sanctioned way to bridge structurally incompatible types.\n return this.db.collection(name) as unknown as DocCollection\n }\n\n async connect(): Promise<void> {\n const { MongoClient: MC } = (await import('mongodb')) as { MongoClient: typeof MongoClient }\n const uri = this.config.uri ?? 'mongodb://localhost:27017'\n this.client = new MC(uri)\n await this.client.connect()\n this.db = this.client.db(this.config.dbName ?? this.config.database ?? 'consenti')\n await this.migrate()\n }\n\n async disconnect(): Promise<void> {\n await this.client.close()\n }\n\n async migrate(): Promise<void> {\n await this.createIndexes()\n await this.seed()\n }\n\n private async createIndexes(): Promise<void> {\n await this.col('consent_records').createIndex({ visitor_id: 1, profile_id: 1 }, { unique: true })\n await this.col('consent_records').createIndex({ tenant_id: 1 })\n await this.col('consent_records').createIndex({ created_at: 1 })\n await this.col('visitors').createIndex({ visitor_id: 1 }, { unique: true })\n await this.col('visitors').createIndex({ tenant_id: 1 })\n await this.col('users').createIndex({ email: 1 }, { unique: true })\n await this.col('audit_logs').createIndex({ tenant_id: 1, created_at: 1 })\n await this.col('user_roles').createIndex({ user_id: 1 })\n await this.col('role_permissions').createIndex({ role_id: 1 })\n }\n\n private async seed(): Promise<void> {\n const { id, name, slug } = SEED_TENANT\n if (!(await this.col('tenants').findOne({ _id: id }))) {\n await this.col('tenants').insertOne({ _id: id, name, slug })\n }\n for (const p of SEED_PERMISSIONS) {\n const doc = { _id: p.id, name: p.name, description: p.description }\n await this.col('permissions').updateOne({ _id: p.id }, { $setOnInsert: doc }, { upsert: true })\n }\n for (const r of SEED_ROLES) {\n const doc = { _id: r.id, tenant_id: r.tenantId, name: r.name, description: r.description }\n await this.col('roles').updateOne({ _id: r.id }, { $setOnInsert: doc }, { upsert: true })\n }\n const rp = this.col('role_permissions')\n for (const { roleId, permissionId } of SEED_ROLE_PERMISSIONS) {\n await rp.updateOne(\n { role_id: roleId, permission_id: permissionId },\n { $setOnInsert: { role_id: roleId, permission_id: permissionId } },\n { upsert: true },\n )\n }\n }\n\n // ── Profiles ─────────────────────────────────────────────────────────────────\n\n async createProfile(data: CreateProfileInput): Promise<Profile> {\n const now = new Date().toISOString()\n const doc: DocProfile = {\n _id: randomUUID(), tenant_id: data.tenantId, name: data.name,\n default_locale: data.defaultLocale, version: 1,\n profile_json: data.profileJson,\n created_at: now, updated_at: now,\n }\n await this.col('profiles').insertOne(doc)\n return mapProfile(doc)\n }\n\n async updateProfile(id: string, data: UpdateProfileInput): Promise<Profile> {\n const now = new Date().toISOString()\n const set: Record<string, unknown> = { updated_at: now }\n if (data.name != null) set['name'] = data.name\n if (data.defaultLocale != null) set['default_locale'] = data.defaultLocale\n if (data.profileJson != null) set['profile_json'] = data.profileJson\n const res = cast<DocProfile>(await this.col('profiles').findOneAndUpdate(\n { _id: id }, { $set: set, $inc: { version: 1 } }, { returnDocument: 'after' },\n ))\n if (!res) throw new Error(`Profile ${id} not found`)\n return mapProfile(res)\n }\n\n async deleteProfile(id: string): Promise<void> {\n await this.col('profiles').deleteOne({ _id: id })\n }\n\n async getProfile(id: string): Promise<Profile | null> {\n const doc = cast<DocProfile>(await this.col('profiles').findOne({ _id: id }))\n return doc ? mapProfile(doc) : null\n }\n\n async getProfiles(tenantId: string): Promise<Profile[]> {\n const docs = castArr<DocProfile>(await this.col('profiles').find({ tenant_id: tenantId }).toArray())\n return docs.map(mapProfile)\n }\n\n // ── Consents ─────────────────────────────────────────────────────────────────\n\n async createConsent(data: CreateConsentInput): Promise<ConsentDbRecord> {\n const now = new Date().toISOString()\n const doc: DocConsent = {\n _id: randomUUID(), tenant_id: data.tenantId, visitor_id: data.visitorId,\n profile_id: data.profileId, profile_version: data.profileVersion,\n locale: data.locale, consent_json: data.consentJson,\n gpc_detected: data.gpcDetected, source: data.source,\n created_at: now, updated_at: now,\n }\n await this.col('consent_records').insertOne(doc)\n await this.writeHistory(doc._id, data.tenantId, data.visitorId, null, data.consentJson, 'created')\n return mapConsent(doc)\n }\n\n async updateConsent(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord> {\n const existing = await this.getConsent(visitorId)\n if (!existing) throw new Error(`Consent for visitor ${visitorId} not found`)\n const now = new Date().toISOString()\n const set: Record<string, unknown> = { updated_at: now, consent_json: data.consentJson }\n if (data.locale != null) set['locale'] = data.locale\n if (data.gpcDetected != null) set['gpc_detected'] = data.gpcDetected\n const res = cast<DocConsent>(await this.col('consent_records').findOneAndUpdate(\n { visitor_id: visitorId }, { $set: set }, { returnDocument: 'after' },\n ))\n if (!res) throw new Error(`Consent for visitor ${visitorId} not found`)\n await this.writeHistory(res._id, res.tenant_id, visitorId, existing.consentJson, data.consentJson, 'updated')\n return mapConsent(res)\n }\n\n async deleteConsent(visitorId: string): Promise<void> {\n await this.col('consent_history').deleteMany({ visitor_id: visitorId })\n await this.col('consent_records').deleteOne({ visitor_id: visitorId })\n }\n\n async getConsent(visitorId: string): Promise<ConsentDbRecord | null> {\n const doc = cast<DocConsent>(await this.col('consent_records').findOne({ visitor_id: visitorId }))\n return doc ? mapConsent(doc) : null\n }\n\n async getConsents(filters: ConsentFilters): Promise<ConsentDbRecord[]> {\n const q = this.buildConsentFilter(filters)\n const page = filters.page ?? 1\n const limit = filters.limit ?? 50\n const docs = castArr<DocConsent>(\n await this.col('consent_records').find(q).sort({ created_at: -1 }).skip((page - 1) * limit).limit(limit).toArray(),\n )\n return docs.map(mapConsent)\n }\n\n async *streamConsents(filters: ConsentFilters): AsyncIterable<ConsentDbRecord> {\n const q = this.buildConsentFilter(filters)\n const cursor = this.col('consent_records').find(q).sort({ created_at: 1 })\n for await (const doc of cursor) yield mapConsent(doc as unknown as DocConsent)\n }\n\n private buildConsentFilter(f: ConsentFilters): Record<string, unknown> {\n const q: Record<string, unknown> = { tenant_id: f.tenantId }\n if (f.profileId != null) q['profile_id'] = f.profileId\n if (f.from != null || f.to != null) {\n const range: Record<string, string> = {}\n if (f.from != null) range['$gte'] = f.from\n if (f.to != null) range['$lte'] = f.to\n q['created_at'] = range\n }\n return q\n }\n\n private async writeHistory(\n consentRecordId: string, tenantId: string, visitorId: string,\n oldJson: ConsentValue | null, newJson: ConsentValue, action: string,\n ): Promise<void> {\n const doc: DocConsentHistory = {\n _id: randomUUID(), tenant_id: tenantId, consent_record_id: consentRecordId,\n visitor_id: visitorId, old_json: oldJson, new_json: newJson,\n action, created_at: new Date().toISOString(),\n }\n await this.col('consent_history').insertOne(doc)\n }\n\n async getConsentHistory(visitorId: string): Promise<ConsentHistoryEntry[]> {\n const docs = castArr<DocConsentHistory>(\n await this.col('consent_history').find({ visitor_id: visitorId }).sort({ created_at: 1 }).toArray(),\n )\n return docs.map(mapHistory)\n }\n\n // ── Visitors ─────────────────────────────────────────────────────────────────\n\n async createVisitor(data: CreateVisitorInput): Promise<Visitor> {\n const now = new Date().toISOString()\n const doc: DocVisitor = {\n _id: randomUUID(), tenant_id: data.tenantId, visitor_id: data.visitorId,\n first_seen: now, last_seen: now,\n ...(data.country != null ? { country: data.country } : {}),\n ...(data.region != null ? { region: data.region } : {}),\n ...(data.city != null ? { city: data.city } : {}),\n ...(data.ipHash != null ? { ip_hash: data.ipHash } : {}),\n ...(data.userAgentHash != null ? { user_agent_hash: data.userAgentHash } : {}),\n }\n await this.col('visitors').insertOne(doc)\n return mapVisitor(doc)\n }\n\n async updateVisitor(visitorId: string, data: UpdateVisitorInput): Promise<Visitor> {\n const set: Record<string, string> = { last_seen: data.lastSeen ?? new Date().toISOString() }\n if (data.country != null) set['country'] = data.country\n if (data.region != null) set['region'] = data.region\n if (data.city != null) set['city'] = data.city\n const res = cast<DocVisitor>(await this.col('visitors').findOneAndUpdate(\n { visitor_id: visitorId }, { $set: set }, { returnDocument: 'after' },\n ))\n if (!res) throw new Error(`Visitor ${visitorId} not found`)\n return mapVisitor(res)\n }\n\n async deleteVisitor(visitorId: string): Promise<void> {\n await this.col('visitors').deleteOne({ visitor_id: visitorId })\n }\n\n async getVisitor(visitorId: string): Promise<Visitor | null> {\n const doc = cast<DocVisitor>(await this.col('visitors').findOne({ visitor_id: visitorId }))\n return doc ? mapVisitor(doc) : null\n }\n\n async getVisitors(filters: VisitorFilters): Promise<Visitor[]> {\n const q: Record<string, unknown> = { tenant_id: filters.tenantId }\n if (filters.from != null || filters.to != null) {\n const r: Record<string, string> = {}\n if (filters.from != null) r['$gte'] = filters.from\n if (filters.to != null) r['$lte'] = filters.to\n q['first_seen'] = r\n }\n const page = filters.page ?? 1\n const limit = filters.limit ?? 50\n const docs = castArr<DocVisitor>(\n await this.col('visitors').find(q).sort({ first_seen: -1 }).skip((page - 1) * limit).limit(limit).toArray(),\n )\n return docs.map(mapVisitor)\n }\n\n // ── Stats ─────────────────────────────────────────────────────────────────────\n\n async getOverviewStats(tenantId: string): Promise<OverviewStats> {\n const [total, gpcCount, visitors] = await Promise.all([\n this.col('consent_records').countDocuments({ tenant_id: tenantId }),\n this.col('consent_records').countDocuments({ tenant_id: tenantId, gpc_detected: true }),\n this.col('visitors').countDocuments({ tenant_id: tenantId }),\n ])\n\n const pipeline = [\n { $match: { tenant_id: tenantId } },\n { $addFields: { values: { $objectToArray: '$consent_json' } } },\n { $unwind: '$values' },\n { $group: { _id: '$values.v', count: { $sum: 1 } } },\n ]\n const results = await this.col('consent_records').aggregate(pipeline).toArray() as Array<{ _id: string; count: number }>\n\n let granted = 0, denied = 0, all = 0\n for (const r of results) {\n all += r.count\n if (r._id === 'granted') granted = r.count\n if (r._id === 'denied') denied = r.count\n }\n return {\n totalConsents: total,\n acceptedPct: all > 0 ? Math.round((granted / all) * 100) : 0,\n rejectedPct: all > 0 ? Math.round((denied / all) * 100) : 0,\n totalVisitors: visitors,\n gpcDetectedCount: gpcCount,\n }\n }\n\n async getCategoryStats(tenantId: string): Promise<CategoryStats> {\n const pipeline = [\n { $match: { tenant_id: tenantId } },\n { $addFields: { pairs: { $objectToArray: '$consent_json' } } },\n { $unwind: '$pairs' },\n { $group: { _id: { cookie: '$pairs.k', status: '$pairs.v' }, count: { $sum: 1 } } },\n ]\n const rows = await this.col('consent_records').aggregate(pipeline).toArray() as Array<{ _id: { cookie: string; status: string }; count: number }>\n const result: CategoryStats = {}\n for (const r of rows) {\n const cookie = r._id.cookie\n if (!result[cookie]) result[cookie] = { granted: 0, denied: 0, objected: 0 }\n const entry = result[cookie]\n if (entry) {\n if (r._id.status === 'granted') entry.granted += r.count\n if (r._id.status === 'denied') entry.denied += r.count\n if (r._id.status === 'objected') entry.objected += r.count\n }\n }\n return result\n }\n\n async getTimeline(tenantId: string, days = 30): Promise<TimelineEntry[]> {\n const from = new Date(Date.now() - days * 86400_000).toISOString()\n const pipeline = [\n { $match: { tenant_id: tenantId, created_at: { $gte: from } } },\n { $group: { _id: { $substr: ['$created_at', 0, 10] }, count: { $sum: 1 } } },\n { $sort: { _id: 1 } },\n ]\n const rows = await this.col('consent_records').aggregate(pipeline).toArray() as Array<{ _id: string; count: number }>\n return rows.map(r => ({ date: r._id, count: r.count }))\n }\n\n // ── Users ─────────────────────────────────────────────────────────────────────\n\n async createUser(data: CreateUserInput): Promise<AdminUser> {\n const now = new Date().toISOString()\n const doc: DocUser = {\n _id: randomUUID(), tenant_id: data.tenantId, name: data.name,\n email: data.email, password_hash: data.passwordHash,\n is_active: true, created_at: now, updated_at: now,\n }\n await this.col('users').insertOne(doc)\n return mapUser(doc)\n }\n\n async updateUser(id: string, data: UpdateUserInput): Promise<AdminUser> {\n const set: Record<string, unknown> = { updated_at: new Date().toISOString() }\n if (data.name != null) set['name'] = data.name\n if (data.email != null) set['email'] = data.email\n if (data.passwordHash != null) set['password_hash'] = data.passwordHash\n if (data.isActive != null) set['is_active'] = data.isActive\n const res = cast<DocUser>(await this.col('users').findOneAndUpdate(\n { _id: id }, { $set: set }, { returnDocument: 'after' },\n ))\n if (!res) throw new Error(`User ${id} not found`)\n return mapUser(res)\n }\n\n async deleteUser(id: string): Promise<void> {\n await this.col('user_roles').deleteMany({ user_id: id })\n await this.col('users').deleteOne({ _id: id })\n }\n\n async getUserById(id: string): Promise<AdminUser | null> {\n const doc = cast<DocUser>(await this.col('users').findOne({ _id: id }))\n return doc ? mapUser(doc) : null\n }\n\n async getUserByEmail(email: string): Promise<AdminUser | null> {\n const doc = cast<DocUser>(await this.col('users').findOne({ email }))\n return doc ? mapUser(doc) : null\n }\n\n async getUsers(tenantId: string): Promise<AdminUser[]> {\n const docs = castArr<DocUser>(await this.col('users').find({ tenant_id: tenantId }).toArray())\n return docs.map(mapUser)\n }\n\n async countUsers(tenantId?: string): Promise<number> {\n return this.col('users').countDocuments(tenantId ? { tenant_id: tenantId } : {})\n }\n\n // ── Roles & permissions ───────────────────────────────────────────────────────\n\n async getRoles(tenantId: string): Promise<Role[]> {\n const docs = castArr<DocRole>(await this.col('roles').find({ tenant_id: tenantId }).toArray())\n return docs.map(mapRole)\n }\n\n async createRole(data: CreateRoleInput): Promise<Role> {\n const doc: DocRole = {\n _id: randomUUID(), tenant_id: data.tenantId, name: data.name,\n ...(data.description != null ? { description: data.description } : {}),\n }\n await this.col('roles').insertOne(doc)\n return mapRole(doc)\n }\n\n async updateRole(id: string, data: UpdateRoleInput): Promise<Role> {\n const set: Record<string, string> = {}\n if (data.name != null) set['name'] = data.name\n if (data.description != null) set['description'] = data.description\n const res = cast<DocRole>(await this.col('roles').findOneAndUpdate(\n { _id: id }, { $set: set }, { returnDocument: 'after' },\n ))\n if (!res) throw new Error(`Role ${id} not found`)\n return mapRole(res)\n }\n\n async deleteRole(id: string): Promise<void> {\n await this.col('role_permissions').deleteMany({ role_id: id })\n await this.col('user_roles').deleteMany({ role_id: id })\n await this.col('roles').deleteOne({ _id: id })\n }\n\n async getAllPermissions(): Promise<Permission[]> {\n const docs = castArr<DocPermission>(await this.col('permissions').find({}).toArray())\n return docs.map(mapPermission)\n }\n\n async getPermissionsForRole(roleId: string): Promise<Permission[]> {\n const rps = castArr<DocRolePermission>(\n await this.col('role_permissions').find({ role_id: roleId }).toArray(),\n )\n const ids = rps.map(r => r.permission_id)\n if (ids.length === 0) return []\n const docs = castArr<DocPermission>(await this.col('permissions').find({ _id: { $in: ids } }).toArray())\n return docs.map(mapPermission)\n }\n\n async getUserRoles(userId: string, tenantId?: string): Promise<Role[]> {\n const filter = tenantId\n ? { user_id: userId, tenant_id: tenantId }\n : { user_id: userId }\n const urs = castArr<DocUserRole>(await this.col('user_roles').find(filter).toArray())\n const ids = urs.map(r => r.role_id)\n if (ids.length === 0) return []\n const docs = castArr<DocRole>(await this.col('roles').find({ _id: { $in: ids } }).toArray())\n return docs.map(mapRole)\n }\n\n async assignRole(userId: string, roleId: string, tenantId = 'default'): Promise<void> {\n await this.col('user_roles').updateOne(\n { user_id: userId, role_id: roleId, tenant_id: tenantId },\n { $setOnInsert: { user_id: userId, role_id: roleId, tenant_id: tenantId } },\n { upsert: true },\n )\n }\n\n async revokeRole(userId: string, roleId: string, tenantId?: string): Promise<void> {\n if (tenantId) {\n await this.col('user_roles').deleteOne({ user_id: userId, role_id: roleId, tenant_id: tenantId })\n } else {\n await this.col('user_roles').deleteMany({ user_id: userId, role_id: roleId })\n }\n }\n\n async assignPermissionToRole(roleId: string, permissionId: string): Promise<void> {\n await this.col('role_permissions').updateOne(\n { role_id: roleId, permission_id: permissionId },\n { $setOnInsert: { role_id: roleId, permission_id: permissionId } },\n { upsert: true },\n )\n }\n\n async revokePermissionFromRole(roleId: string, permissionId: string): Promise<void> {\n await this.col('role_permissions').deleteOne({ role_id: roleId, permission_id: permissionId })\n }\n\n // ── Audit logs ────────────────────────────────────────────────────────────────\n\n async createLog(data: CreateAuditLogInput): Promise<void> {\n const doc: DocAuditLog = {\n _id: randomUUID(), tenant_id: data.tenantId, action: data.action,\n resource_type: data.resourceType,\n ...(data.userId != null ? { user_id: data.userId } : {}),\n ...(data.resourceId != null ? { resource_id: data.resourceId } : {}),\n ...(data.oldData != null ? { old_data: data.oldData } : {}),\n ...(data.newData != null ? { new_data: data.newData } : {}),\n created_at: new Date().toISOString(),\n }\n await this.col('audit_logs').insertOne(doc)\n }\n\n async getLogs(filters: AuditFilters): Promise<AuditLog[]> {\n const q = this.buildAuditFilter(filters)\n const page = filters.page ?? 1\n const limit = filters.limit ?? 50\n const docs = castArr<DocAuditLog>(\n await this.col('audit_logs').find(q).sort({ created_at: -1 }).skip((page - 1) * limit).limit(limit).toArray(),\n )\n return docs.map(mapAuditLog)\n }\n\n async *streamAuditLogs(filters: AuditFilters): AsyncIterable<AuditLog> {\n const q = this.buildAuditFilter(filters)\n const cursor = this.col('audit_logs').find(q).sort({ created_at: 1 })\n for await (const doc of cursor) yield mapAuditLog(doc as unknown as DocAuditLog)\n }\n\n private buildAuditFilter(f: AuditFilters): Record<string, unknown> {\n const q: Record<string, unknown> = { tenant_id: f.tenantId }\n if (f.action != null) q['action'] = f.action\n if (f.resourceType != null) q['resource_type'] = f.resourceType\n if (f.from != null || f.to != null) {\n const r: Record<string, string> = {}\n if (f.from != null) r['$gte'] = f.from\n if (f.to != null) r['$lte'] = f.to\n q['created_at'] = r\n }\n return q\n }\n\n // ── Stats extensions ──────────────────────────────────────────────────────────\n\n async getCountries(tenantId: string): Promise<CountryStat[]> {\n const pipeline = [\n { $match: { tenant_id: tenantId } },\n { $lookup: { from: 'visitors', localField: 'visitor_id', foreignField: 'visitor_id', as: 'v' } },\n { $unwind: '$v' },\n { $match: { 'v.country': { $ne: null } } },\n { $group: { _id: '$v.country', count: { $sum: 1 } } },\n { $sort: { count: -1 } },\n { $limit: 50 },\n ]\n const rows = await this.col('consent_records').aggregate(pipeline).toArray() as Array<{ _id: string; count: number }>\n return rows.map(r => ({ country: r._id, count: r.count }))\n }\n\n async getGpcStats(tenantId: string): Promise<GpcStats> {\n const total = await this.col('consent_records').countDocuments({ tenant_id: tenantId })\n const detected = await this.col('consent_records').countDocuments({ tenant_id: tenantId, gpc_detected: true })\n return { detected, total, rate: total > 0 ? Math.round((detected / total) * 100) : 0 }\n }\n\n // ── Tenants ───────────────────────────────────────────────────────────────────\n\n async getTenants(): Promise<Tenant[]> {\n const docs = castArr<{ _id: string; name: string; slug: string; created_at: string; updated_at: string }>(\n await this.col('tenants').find({}).toArray()\n )\n return docs.map(d => ({ id: d._id, name: d.name, slug: d.slug, createdAt: d.created_at, updatedAt: d.updated_at }))\n }\n\n // ── API Keys ──────────────────────────────────────────────────────────────────\n\n async createApiKey(data: CreateApiKeyInput): Promise<ApiKey> {\n const doc: DocApiKey = {\n _id: randomUUID(), tenant_id: data.tenantId, key_hash: data.keyHash,\n name: data.name, is_active: true, created_at: new Date().toISOString(),\n }\n await this.col('api_keys').insertOne(doc)\n return { id: doc._id, tenantId: doc.tenant_id, keyHash: doc.key_hash, name: doc.name, isActive: doc.is_active, createdAt: doc.created_at }\n }\n\n async getApiKeyByHash(keyHash: string): Promise<ApiKey | null> {\n const doc = cast<DocApiKey>(await this.col('api_keys').findOne({ key_hash: keyHash, is_active: true }))\n if (!doc) return null\n return { id: doc._id, tenantId: doc.tenant_id, keyHash: doc.key_hash, name: doc.name, isActive: doc.is_active, createdAt: doc.created_at }\n }\n\n async revokeApiKey(id: string): Promise<void> {\n await this.col('api_keys').updateOne({ _id: id }, { $set: { is_active: false } })\n }\n\n async getApiKeys(tenantId: string): Promise<ApiKey[]> {\n const docs = castArr<DocApiKey>(await this.col('api_keys').find({ tenant_id: tenantId }).sort({ created_at: -1 }).toArray())\n return docs.map(d => ({ id: d._id, tenantId: d.tenant_id, keyHash: d.key_hash, name: d.name, isActive: d.is_active, createdAt: d.created_at }))\n }\n\n async createTenant(data: CreateTenantInput): Promise<Tenant> {\n const id = randomUUID()\n const now = new Date().toISOString()\n const doc = { _id: id, name: data.name, slug: data.slug, created_at: now, updated_at: now }\n await this.col('tenants').insertOne(doc)\n return { id, name: data.name, slug: data.slug, createdAt: now, updatedAt: now }\n }\n\n async updateTenant(id: string, data: UpdateTenantInput): Promise<Tenant> {\n const now = new Date().toISOString()\n const update: Record<string, string> = { updated_at: now }\n if (data.name != null) update['name'] = data.name\n if (data.slug != null) update['slug'] = data.slug\n await this.col('tenants').updateOne({ _id: id }, { $set: update })\n const doc = cast<{ _id: string; name: string; slug: string; created_at: string; updated_at: string }>(\n await this.col('tenants').findOne({ _id: id })\n )\n if (!doc) throw new Error(`Tenant ${id} not found`)\n return { id: doc._id, name: doc.name, slug: doc.slug, createdAt: doc.created_at, updatedAt: doc.updated_at }\n }\n\n async deleteTenant(id: string): Promise<void> {\n await this.col('tenants').deleteOne({ _id: id })\n }\n\n async purgeExpiredConsents(olderThanDays: number): Promise<number> {\n const cutoff = new Date(Date.now() - olderThanDays * 86_400_000).toISOString()\n const docs = castArr<{ visitor_id: string }>(\n await this.col('consent_records').find({ created_at: { $lt: cutoff } }).toArray()\n )\n if (docs.length === 0) return 0\n const visitorIds = docs.map(d => d.visitor_id)\n await this.col('consent_history').deleteMany({ visitor_id: { $in: visitorIds } })\n await this.col('consent_records').deleteMany({ visitor_id: { $in: visitorIds } })\n return docs.length\n }\n\n // Template methods — not yet implemented for MongoDB adapter\n async createCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async updateCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async deleteCookieTemplate(): Promise<void> { throw new Error('Not implemented') }\n async getCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async getCookieTemplates(): Promise<never> { throw new Error('Not implemented') }\n async copyCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async createUITemplate(): Promise<never> { throw new Error('Not implemented') }\n async updateUITemplate(): Promise<never> { throw new Error('Not implemented') }\n async deleteUITemplate(): Promise<void> { throw new Error('Not implemented') }\n async getUITemplate(): Promise<never> { throw new Error('Not implemented') }\n async getUITemplates(): Promise<never> { throw new Error('Not implemented') }\n async copyUITemplate(): Promise<never> { throw new Error('Not implemented') }\n}\n","import type { Pool, PoolConnection, RowDataPacket, ResultSetHeader } from 'mysql2/promise'\nimport { randomUUID } from '../../utils/crypto'\nimport { SEED_TENANT, SEED_PERMISSIONS, SEED_ROLES, SEED_ROLE_PERMISSIONS, SCHEMA_SQL_MYSQL } from '../seed-data'\nimport type {\n StorageAdapter, StorageConfig, Profile, ProfileConfig,\n CreateProfileInput, UpdateProfileInput,\n ConsentDbRecord, ConsentHistoryEntry, ConsentValue, ConsentFilters,\n CreateConsentInput, UpdateConsentInput,\n Visitor, VisitorFilters, CreateVisitorInput, UpdateVisitorInput,\n AdminUser, CreateUserInput, UpdateUserInput,\n Role, CreateRoleInput, UpdateRoleInput,\n Permission, AuditLog, AuditFilters, CreateAuditLogInput,\n OverviewStats, CategoryStats, TimelineEntry,\n CountryStat, GpcStats, Tenant, ApiKey, CreateApiKeyInput,\n CreateTenantInput, UpdateTenantInput,\n} from '@consenti/types'\n\n// ── Raw row shapes ─────────────────────────────────────────────────────────────\n\ninterface RowProfile extends RowDataPacket {\n id: string; tenant_id: string; name: string; default_locale: string\n version: number; profile_json: string\n created_at: string; updated_at: string\n}\ninterface RowConsent extends RowDataPacket {\n id: string; tenant_id: string; visitor_id: string; profile_id: string\n profile_version: number; locale: string; consent_json: string\n gpc_detected: number; source: string; created_at: string; updated_at: string\n age_verified?: number; parental_consent_token?: string | null; tcf_string?: string | null\n}\ninterface RowConsentHistory extends RowDataPacket {\n id: string; tenant_id: string; consent_record_id: string; visitor_id: string\n old_json: string | null; new_json: string; action: string; created_at: string\n}\ninterface RowVisitor extends RowDataPacket {\n id: string; tenant_id: string; visitor_id: string\n country: string | null; region: string | null; city: string | null\n ip_hash: string | null; user_agent_hash: string | null\n first_seen: string; last_seen: string\n}\ninterface RowUser extends RowDataPacket {\n id: string; tenant_id: string; name: string; email: string\n password_hash: string; is_active: number; created_at: string; updated_at: string\n totp_secret?: string | null; totp_enabled?: number\n}\ninterface RowRole extends RowDataPacket {\n id: string; tenant_id: string; name: string; description: string | null\n}\ninterface RowPermission extends RowDataPacket {\n id: string; name: string; description: string | null\n}\ninterface RowAuditLog extends RowDataPacket {\n id: string; tenant_id: string; user_id: string | null; action: string\n resource_type: string; resource_id: string | null\n old_data: string | null; new_data: string | null; created_at: string\n}\ninterface RowCount extends RowDataPacket { total: number }\ninterface RowStatus extends RowDataPacket { status: string; count: number }\ninterface RowDateCount extends RowDataPacket { date: string; count: number }\ninterface RowCookieStatus extends RowDataPacket { cookie_id: string; status: string; count: number }\ninterface RowCountry extends RowDataPacket { country: string; count: number }\ninterface RowApiKey extends RowDataPacket {\n id: string; tenant_id: string; key_hash: string; name: string; is_active: number; created_at: string\n}\ninterface RowTenant extends RowDataPacket { id: string; name: string; slug: string; created_at: string; updated_at: string }\n\n// ── Mappers ────────────────────────────────────────────────────────────────────\n\nfunction mapProfile(r: RowProfile): Profile {\n return {\n id: r.id, tenantId: r.tenant_id, name: r.name,\n defaultLocale: r.default_locale, version: r.version,\n profileJson: JSON.parse(r.profile_json) as ProfileConfig,\n createdAt: r.created_at, updatedAt: r.updated_at,\n }\n}\n\nfunction mapConsent(r: RowConsent): ConsentDbRecord {\n return {\n id: r.id, tenantId: r.tenant_id, visitorId: r.visitor_id, profileId: r.profile_id,\n profileVersion: r.profile_version, locale: r.locale,\n consentJson: JSON.parse(r.consent_json) as ConsentValue,\n gpcDetected: r.gpc_detected === 1, source: r.source as ConsentDbRecord['source'],\n createdAt: r.created_at, updatedAt: r.updated_at,\n ...(r.age_verified != null ? { ageVerified: r.age_verified === 1 } : {}),\n ...(r.parental_consent_token != null ? { parentalConsentToken: r.parental_consent_token } : {}),\n ...(r.tcf_string != null ? { tcfString: r.tcf_string } : {}),\n }\n}\n\nfunction mapHistory(r: RowConsentHistory): ConsentHistoryEntry {\n return {\n id: r.id, tenantId: r.tenant_id, consentRecordId: r.consent_record_id,\n visitorId: r.visitor_id,\n oldJson: r.old_json ? JSON.parse(r.old_json) as ConsentValue : null,\n newJson: JSON.parse(r.new_json) as ConsentValue,\n action: r.action as ConsentHistoryEntry['action'], createdAt: r.created_at,\n }\n}\n\nfunction mapVisitor(r: RowVisitor): Visitor {\n return {\n id: r.id, tenantId: r.tenant_id, visitorId: r.visitor_id,\n ...(r.country != null ? { country: r.country } : {}),\n ...(r.region != null ? { region: r.region } : {}),\n ...(r.city != null ? { city: r.city } : {}),\n ...(r.ip_hash != null ? { ipHash: r.ip_hash } : {}),\n ...(r.user_agent_hash!= null ? { userAgentHash: r.user_agent_hash} : {}),\n firstSeen: r.first_seen, lastSeen: r.last_seen,\n }\n}\n\nfunction mapUser(r: RowUser): AdminUser {\n return {\n id: r.id, tenantId: r.tenant_id, name: r.name, email: r.email,\n passwordHash: r.password_hash, isActive: r.is_active === 1,\n createdAt: r.created_at, updatedAt: r.updated_at,\n totpEnabled: r.totp_enabled === 1,\n ...(r.totp_secret != null ? { totpSecret: r.totp_secret } : {}),\n }\n}\n\nfunction mapRole(r: RowRole): Role {\n return {\n id: r.id, tenantId: r.tenant_id, name: r.name,\n ...(r.description != null ? { description: r.description } : {}),\n }\n}\n\nfunction mapPermission(r: RowPermission): Permission {\n return {\n id: r.id, name: r.name,\n ...(r.description != null ? { description: r.description } : {}),\n }\n}\n\nfunction mapAuditLog(r: RowAuditLog): AuditLog {\n return {\n id: r.id, tenantId: r.tenant_id, action: r.action, resourceType: r.resource_type,\n ...(r.user_id != null ? { userId: r.user_id } : {}),\n ...(r.resource_id != null ? { resourceId: r.resource_id } : {}),\n ...(r.old_data != null ? { oldData: JSON.parse(r.old_data) as unknown } : {}),\n ...(r.new_data != null ? { newData: JSON.parse(r.new_data) as unknown } : {}),\n createdAt: r.created_at,\n }\n}\n\n// ── Adapter ────────────────────────────────────────────────────────────────────\n\nexport class MySQLAdapter implements StorageAdapter {\n private pool!: Pool\n\n constructor(private config: StorageConfig) {}\n\n private async q<T extends RowDataPacket>(sql: string, params: (string | number | boolean | null)[] = []): Promise<T[]> {\n const [rows] = await this.pool.query<T[]>(sql, params)\n return rows\n }\n\n private async exec(sql: string, params: (string | number | boolean | null)[] = []): Promise<ResultSetHeader> {\n const [result] = await this.pool.query<ResultSetHeader>(sql, params)\n return result\n }\n\n async connect(): Promise<void> {\n const mysql = (await import('mysql2/promise')) as { createPool: typeof import('mysql2/promise').createPool }\n const cfg = this.config\n if (cfg.uri) {\n this.pool = mysql.createPool(cfg.uri)\n } else {\n this.pool = mysql.createPool({\n host: cfg.host ?? 'localhost',\n port: cfg.port ?? 3306,\n user: cfg.user ?? 'root',\n password: cfg.password ?? '',\n database: cfg.database ?? cfg.dbName ?? 'consenti',\n })\n }\n await this.migrate()\n }\n\n async disconnect(): Promise<void> {\n await this.pool.end()\n }\n\n async migrate(): Promise<void> {\n const conn: PoolConnection = await this.pool.getConnection()\n try {\n const [tables] = await conn.query<RowDataPacket[]>('SHOW TABLES LIKE ?', ['schema_version'])\n if (tables.length === 0) {\n for (const stmt of SCHEMA_SQL_MYSQL.split(';').map(s => s.trim()).filter(Boolean)) {\n await conn.query(stmt)\n }\n await this.seed(conn)\n await conn.query('INSERT IGNORE INTO schema_version (version) VALUES (2)')\n return\n }\n const [vrows] = await conn.query<RowDataPacket[]>('SELECT version FROM schema_version ORDER BY version DESC LIMIT 1')\n const version = (vrows[0] as { version?: number } | undefined)?.version ?? 0\n if (version < 2) {\n const alters = [\n 'ALTER TABLE consent_records ADD COLUMN IF NOT EXISTS age_verified TINYINT(1) NOT NULL DEFAULT 0',\n 'ALTER TABLE consent_records ADD COLUMN IF NOT EXISTS parental_consent_token TEXT',\n 'ALTER TABLE consent_records ADD COLUMN IF NOT EXISTS tcf_string TEXT',\n 'ALTER TABLE users ADD COLUMN IF NOT EXISTS totp_secret TEXT',\n 'ALTER TABLE users ADD COLUMN IF NOT EXISTS totp_enabled TINYINT(1) NOT NULL DEFAULT 0',\n ]\n for (const stmt of alters) await conn.query(stmt)\n await conn.query('INSERT IGNORE INTO schema_version (version) VALUES (2)')\n }\n if (version < 3) {\n await conn.query('ALTER TABLE user_roles ADD COLUMN IF NOT EXISTS tenant_id VARCHAR(36) NOT NULL DEFAULT \\'default\\'')\n await conn.query('INSERT IGNORE INTO schema_version (version) VALUES (3)')\n }\n } finally {\n conn.release()\n }\n }\n\n private async seed(conn: PoolConnection): Promise<void> {\n await conn.query('INSERT IGNORE INTO tenants (id, name, slug) VALUES (?,?,?)', [SEED_TENANT.id, SEED_TENANT.name, SEED_TENANT.slug])\n for (const p of SEED_PERMISSIONS) {\n await conn.query('INSERT IGNORE INTO permissions (id, name, description) VALUES (?,?,?)', [p.id, p.name, p.description])\n }\n for (const r of SEED_ROLES) {\n await conn.query('INSERT IGNORE INTO roles (id, tenant_id, name, description) VALUES (?,?,?,?)', [r.id, r.tenantId, r.name, r.description])\n }\n for (const { roleId, permissionId } of SEED_ROLE_PERMISSIONS) {\n await conn.query('INSERT IGNORE INTO role_permissions (role_id, permission_id) VALUES (?,?)', [roleId, permissionId])\n }\n }\n\n // ── Profiles ─────────────────────────────────────────────────────────────────\n\n async createProfile(data: CreateProfileInput): Promise<Profile> {\n const id = randomUUID()\n await this.exec(\n 'INSERT INTO profiles (id, tenant_id, name, default_locale, profile_json) VALUES (?,?,?,?,?)',\n [id, data.tenantId, data.name, data.defaultLocale, JSON.stringify(data.profileJson)],\n )\n const rows = await this.q<RowProfile>('SELECT * FROM profiles WHERE id=?', [id])\n const row = rows[0]\n if (!row) throw new Error('Profile creation failed')\n return mapProfile(row)\n }\n\n async updateProfile(id: string, data: UpdateProfileInput): Promise<Profile> {\n const sets: string[] = ['version = version + 1']\n const vals: (string | number | boolean | null)[] = []\n if (data.name != null) { sets.push('name=?'); vals.push(data.name) }\n if (data.defaultLocale != null){ sets.push('default_locale=?'); vals.push(data.defaultLocale) }\n if (data.profileJson != null) { sets.push('profile_json=?'); vals.push(JSON.stringify(data.profileJson)) }\n vals.push(id)\n await this.exec(`UPDATE profiles SET ${sets.join(',')} WHERE id=?`, vals)\n const rows = await this.q<RowProfile>('SELECT * FROM profiles WHERE id=?', [id])\n const row = rows[0]\n if (!row) throw new Error(`Profile ${id} not found`)\n return mapProfile(row)\n }\n\n async deleteProfile(id: string): Promise<void> {\n await this.exec('DELETE FROM profiles WHERE id=?', [id])\n }\n\n async getProfile(id: string): Promise<Profile | null> {\n const rows = await this.q<RowProfile>('SELECT * FROM profiles WHERE id=?', [id])\n return rows[0] ? mapProfile(rows[0]) : null\n }\n\n async getProfiles(tenantId: string): Promise<Profile[]> {\n const rows = await this.q<RowProfile>('SELECT * FROM profiles WHERE tenant_id=? ORDER BY created_at DESC', [tenantId])\n return rows.map(mapProfile)\n }\n\n // ── Consents ─────────────────────────────────────────────────────────────────\n\n async createConsent(data: CreateConsentInput): Promise<ConsentDbRecord> {\n const id = randomUUID()\n await this.exec(\n 'INSERT INTO consent_records (id, tenant_id, visitor_id, profile_id, profile_version, locale, consent_json, gpc_detected, source) VALUES (?,?,?,?,?,?,?,?,?)',\n [id, data.tenantId, data.visitorId, data.profileId, data.profileVersion, data.locale,\n JSON.stringify(data.consentJson), data.gpcDetected ? 1 : 0, data.source],\n )\n const rows = await this.q<RowConsent>('SELECT * FROM consent_records WHERE id=?', [id])\n const row = rows[0]\n if (!row) throw new Error('Consent creation failed')\n await this.writeHistory(id, data.tenantId, data.visitorId, null, data.consentJson, 'created')\n return mapConsent(row)\n }\n\n async updateConsent(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord> {\n const existing = await this.getConsent(visitorId)\n if (!existing) throw new Error(`Consent for visitor ${visitorId} not found`)\n const sets: string[] = ['consent_json=?']\n const vals: (string | number | boolean | null)[] = [JSON.stringify(data.consentJson)]\n if (data.locale != null) { sets.push('locale=?'); vals.push(data.locale) }\n if (data.gpcDetected != null) { sets.push('gpc_detected=?'); vals.push(data.gpcDetected ? 1 : 0) }\n vals.push(visitorId)\n await this.exec(`UPDATE consent_records SET ${sets.join(',')} WHERE visitor_id=?`, vals)\n const rows = await this.q<RowConsent>('SELECT * FROM consent_records WHERE visitor_id=?', [visitorId])\n const row = rows[0]\n if (!row) throw new Error(`Consent for visitor ${visitorId} not found`)\n await this.writeHistory(row.id, row.tenant_id, visitorId, existing.consentJson, data.consentJson, 'updated')\n return mapConsent(row)\n }\n\n async deleteConsent(visitorId: string): Promise<void> {\n await this.exec('DELETE FROM consent_history WHERE visitor_id=?', [visitorId])\n await this.exec('DELETE FROM consent_records WHERE visitor_id=?', [visitorId])\n }\n\n async getConsent(visitorId: string): Promise<ConsentDbRecord | null> {\n const rows = await this.q<RowConsent>('SELECT * FROM consent_records WHERE visitor_id=?', [visitorId])\n return rows[0] ? mapConsent(rows[0]) : null\n }\n\n async getConsents(filters: ConsentFilters): Promise<ConsentDbRecord[]> {\n const { sql, params } = this.buildConsentQuery(filters)\n const page = filters.page ?? 1\n const limit = filters.limit ?? 50\n const rows = await this.q<RowConsent>(`${sql} ORDER BY created_at DESC LIMIT ? OFFSET ?`, [...params, limit, (page - 1) * limit])\n return rows.map(mapConsent)\n }\n\n async *streamConsents(filters: ConsentFilters): AsyncIterable<ConsentDbRecord> {\n const { sql, params } = this.buildConsentQuery(filters)\n const rows = await this.q<RowConsent>(`${sql} ORDER BY created_at ASC`, params)\n for (const r of rows) yield mapConsent(r)\n }\n\n private buildConsentQuery(f: ConsentFilters): { sql: string; params: (string | number | boolean | null)[] } {\n let sql = 'SELECT * FROM consent_records WHERE tenant_id=?'\n const params: (string | number | boolean | null)[] = [f.tenantId]\n if (f.profileId != null) { sql += ' AND profile_id=?'; params.push(f.profileId) }\n if (f.from != null) { sql += ' AND created_at>=?'; params.push(f.from) }\n if (f.to != null) { sql += ' AND created_at<=?'; params.push(f.to) }\n return { sql, params }\n }\n\n private async writeHistory(\n consentRecordId: string, tenantId: string, visitorId: string,\n oldJson: ConsentValue | null, newJson: ConsentValue, action: string,\n ): Promise<void> {\n await this.exec(\n 'INSERT INTO consent_history (id, tenant_id, consent_record_id, visitor_id, old_json, new_json, action) VALUES (?,?,?,?,?,?,?)',\n [randomUUID(), tenantId, consentRecordId, visitorId,\n oldJson ? JSON.stringify(oldJson) : null, JSON.stringify(newJson), action],\n )\n }\n\n async getConsentHistory(visitorId: string): Promise<ConsentHistoryEntry[]> {\n const rows = await this.q<RowConsentHistory>('SELECT * FROM consent_history WHERE visitor_id=? ORDER BY created_at ASC', [visitorId])\n return rows.map(mapHistory)\n }\n\n // ── Visitors ─────────────────────────────────────────────────────────────────\n\n async createVisitor(data: CreateVisitorInput): Promise<Visitor> {\n const id = randomUUID()\n await this.exec(\n 'INSERT INTO visitors (id, tenant_id, visitor_id, country, region, city, ip_hash, user_agent_hash) VALUES (?,?,?,?,?,?,?,?)',\n [id, data.tenantId, data.visitorId,\n data.country ?? null, data.region ?? null, data.city ?? null,\n data.ipHash ?? null, data.userAgentHash ?? null],\n )\n const rows = await this.q<RowVisitor>('SELECT * FROM visitors WHERE id=?', [id])\n const row = rows[0]\n if (!row) throw new Error('Visitor creation failed')\n return mapVisitor(row)\n }\n\n async updateVisitor(visitorId: string, data: UpdateVisitorInput): Promise<Visitor> {\n const sets: string[] = ['last_seen=NOW()']\n const vals: (string | number | boolean | null)[] = []\n if (data.country != null) { sets.push('country=?'); vals.push(data.country) }\n if (data.region != null) { sets.push('region=?'); vals.push(data.region) }\n if (data.city != null) { sets.push('city=?'); vals.push(data.city) }\n vals.push(visitorId)\n await this.exec(`UPDATE visitors SET ${sets.join(',')} WHERE visitor_id=?`, vals)\n const rows = await this.q<RowVisitor>('SELECT * FROM visitors WHERE visitor_id=?', [visitorId])\n const row = rows[0]\n if (!row) throw new Error(`Visitor ${visitorId} not found`)\n return mapVisitor(row)\n }\n\n async deleteVisitor(visitorId: string): Promise<void> {\n await this.exec('DELETE FROM visitors WHERE visitor_id=?', [visitorId])\n }\n\n async getVisitor(visitorId: string): Promise<Visitor | null> {\n const rows = await this.q<RowVisitor>('SELECT * FROM visitors WHERE visitor_id=?', [visitorId])\n return rows[0] ? mapVisitor(rows[0]) : null\n }\n\n async getVisitors(filters: VisitorFilters): Promise<Visitor[]> {\n let sql = 'SELECT * FROM visitors WHERE tenant_id=?'\n const params: (string | number | boolean | null)[] = [filters.tenantId]\n if (filters.from != null) { sql += ' AND first_seen>=?'; params.push(filters.from) }\n if (filters.to != null) { sql += ' AND first_seen<=?'; params.push(filters.to) }\n const page = filters.page ?? 1\n const limit = filters.limit ?? 50\n const rows = await this.q<RowVisitor>(`${sql} ORDER BY first_seen DESC LIMIT ? OFFSET ?`, [...params, limit, (page - 1) * limit])\n return rows.map(mapVisitor)\n }\n\n // ── Stats ─────────────────────────────────────────────────────────────────────\n\n async getOverviewStats(tenantId: string): Promise<OverviewStats> {\n const [[countRow], [gpcRow], [visitorRow]] = await Promise.all([\n this.q<RowCount>('SELECT COUNT(*) AS total FROM consent_records WHERE tenant_id=?', [tenantId]),\n this.q<RowCount>('SELECT COUNT(*) AS total FROM consent_records WHERE tenant_id=? AND gpc_detected=1', [tenantId]),\n this.q<RowCount>('SELECT COUNT(*) AS total FROM visitors WHERE tenant_id=?', [tenantId]),\n ])\n const total = countRow?.total ?? 0\n const gpcCount = gpcRow?.total ?? 0\n const visitors = visitorRow?.total ?? 0\n\n const statusRows = await this.q<RowStatus>(\n `SELECT jt.status, COUNT(*) AS count\n FROM consent_records cr\n JOIN JSON_TABLE(cr.consent_json, '$.*' COLUMNS (status VARCHAR(20) PATH '$')) AS jt\n WHERE cr.tenant_id=?\n GROUP BY jt.status`,\n [tenantId],\n )\n let granted = 0, denied = 0, all = 0\n for (const r of statusRows) {\n all += r.count\n if (r.status === 'granted') granted = r.count\n if (r.status === 'denied') denied = r.count\n }\n return {\n totalConsents: total,\n acceptedPct: all > 0 ? Math.round((granted / all) * 100) : 0,\n rejectedPct: all > 0 ? Math.round((denied / all) * 100) : 0,\n totalVisitors: visitors,\n gpcDetectedCount: gpcCount,\n }\n }\n\n async getCategoryStats(tenantId: string): Promise<CategoryStats> {\n const rows = await this.q<RowCookieStatus>(\n `SELECT jt.cookie_id, jt.status, COUNT(*) AS count\n FROM consent_records cr\n JOIN JSON_TABLE(cr.consent_json, '$.*' COLUMNS (NESTED PATH '$' COLUMNS (\n cookie_id VARCHAR(100) PATH '$.k',\n status VARCHAR(20) PATH '$.v'\n ))) AS jt\n WHERE cr.tenant_id=?\n GROUP BY jt.cookie_id, jt.status`,\n [tenantId],\n )\n const result: CategoryStats = {}\n for (const r of rows) {\n if (!result[r.cookie_id]) result[r.cookie_id] = { granted: 0, denied: 0, objected: 0 }\n const entry = result[r.cookie_id]\n if (entry) {\n if (r.status === 'granted') entry.granted += r.count\n if (r.status === 'denied') entry.denied += r.count\n if (r.status === 'objected') entry.objected += r.count\n }\n }\n return result\n }\n\n async getTimeline(tenantId: string, days = 30): Promise<TimelineEntry[]> {\n const from = new Date(Date.now() - days * 86400_000).toISOString().slice(0, 10)\n const rows = await this.q<RowDateCount>(\n `SELECT DATE(created_at) AS date, COUNT(*) AS count\n FROM consent_records WHERE tenant_id=? AND created_at>=?\n GROUP BY DATE(created_at) ORDER BY date ASC`,\n [tenantId, from],\n )\n return rows.map(r => ({ date: String(r.date), count: r.count }))\n }\n\n // ── Users ─────────────────────────────────────────────────────────────────────\n\n async createUser(data: CreateUserInput): Promise<AdminUser> {\n const id = randomUUID()\n await this.exec(\n 'INSERT INTO users (id, tenant_id, name, email, password_hash) VALUES (?,?,?,?,?)',\n [id, data.tenantId, data.name, data.email, data.passwordHash],\n )\n const rows = await this.q<RowUser>('SELECT * FROM users WHERE id=?', [id])\n const row = rows[0]\n if (!row) throw new Error('User creation failed')\n return mapUser(row)\n }\n\n async updateUser(id: string, data: UpdateUserInput): Promise<AdminUser> {\n const sets: string[] = []\n const vals: (string | number | boolean | null)[] = []\n if (data.name != null) { sets.push('name=?'); vals.push(data.name) }\n if (data.email != null) { sets.push('email=?'); vals.push(data.email) }\n if (data.passwordHash != null) { sets.push('password_hash=?'); vals.push(data.passwordHash) }\n if (data.isActive != null) { sets.push('is_active=?'); vals.push(data.isActive ? 1 : 0) }\n if (sets.length > 0) { vals.push(id); await this.exec(`UPDATE users SET ${sets.join(',')} WHERE id=?`, vals) }\n const rows = await this.q<RowUser>('SELECT * FROM users WHERE id=?', [id])\n const row = rows[0]\n if (!row) throw new Error(`User ${id} not found`)\n return mapUser(row)\n }\n\n async deleteUser(id: string): Promise<void> {\n await this.exec('DELETE FROM user_roles WHERE user_id=?', [id])\n await this.exec('DELETE FROM users WHERE id=?', [id])\n }\n\n async getUserById(id: string): Promise<AdminUser | null> {\n const rows = await this.q<RowUser>('SELECT * FROM users WHERE id=?', [id])\n return rows[0] ? mapUser(rows[0]) : null\n }\n\n async getUserByEmail(email: string): Promise<AdminUser | null> {\n const rows = await this.q<RowUser>('SELECT * FROM users WHERE email=?', [email])\n return rows[0] ? mapUser(rows[0]) : null\n }\n\n async getUsers(tenantId: string): Promise<AdminUser[]> {\n const rows = await this.q<RowUser>('SELECT * FROM users WHERE tenant_id=? ORDER BY created_at DESC', [tenantId])\n return rows.map(mapUser)\n }\n\n async countUsers(tenantId?: string): Promise<number> {\n const rows = tenantId\n ? await this.q<RowCount>('SELECT COUNT(*) AS total FROM users WHERE tenant_id=?', [tenantId])\n : await this.q<RowCount>('SELECT COUNT(*) AS total FROM users')\n return rows[0]?.total ?? 0\n }\n\n // ── Roles & permissions ───────────────────────────────────────────────────────\n\n async getRoles(tenantId: string): Promise<Role[]> {\n const rows = await this.q<RowRole>('SELECT * FROM roles WHERE tenant_id=?', [tenantId])\n return rows.map(mapRole)\n }\n\n async createRole(data: CreateRoleInput): Promise<Role> {\n const id = randomUUID()\n await this.exec(\n 'INSERT INTO roles (id, tenant_id, name, description) VALUES (?,?,?,?)',\n [id, data.tenantId, data.name, data.description ?? null],\n )\n const rows = await this.q<RowRole>('SELECT * FROM roles WHERE id=?', [id])\n const row = rows[0]\n if (!row) throw new Error('Role creation failed')\n return mapRole(row)\n }\n\n async updateRole(id: string, data: UpdateRoleInput): Promise<Role> {\n const sets: string[] = []\n const vals: (string | number | boolean | null)[] = []\n if (data.name != null) { sets.push('name=?'); vals.push(data.name) }\n if (data.description != null) { sets.push('description=?'); vals.push(data.description) }\n if (sets.length > 0) { vals.push(id); await this.exec(`UPDATE roles SET ${sets.join(',')} WHERE id=?`, vals) }\n const rows = await this.q<RowRole>('SELECT * FROM roles WHERE id=?', [id])\n const row = rows[0]\n if (!row) throw new Error(`Role ${id} not found`)\n return mapRole(row)\n }\n\n async deleteRole(id: string): Promise<void> {\n await this.exec('DELETE FROM role_permissions WHERE role_id=?', [id])\n await this.exec('DELETE FROM user_roles WHERE role_id=?', [id])\n await this.exec('DELETE FROM roles WHERE id=?', [id])\n }\n\n async getAllPermissions(): Promise<Permission[]> {\n const rows = await this.q<RowPermission>('SELECT * FROM permissions ORDER BY name')\n return rows.map(mapPermission)\n }\n\n async getPermissionsForRole(roleId: string): Promise<Permission[]> {\n const rows = await this.q<RowPermission>(\n 'SELECT p.* FROM permissions p JOIN role_permissions rp ON p.id=rp.permission_id WHERE rp.role_id=?',\n [roleId],\n )\n return rows.map(mapPermission)\n }\n\n async getUserRoles(userId: string, tenantId?: string): Promise<Role[]> {\n const rows = tenantId\n ? await this.q<RowRole>(\n 'SELECT r.* FROM roles r JOIN user_roles ur ON r.id=ur.role_id WHERE ur.user_id=? AND ur.tenant_id=?',\n [userId, tenantId],\n )\n : await this.q<RowRole>(\n 'SELECT r.* FROM roles r JOIN user_roles ur ON r.id=ur.role_id WHERE ur.user_id=?',\n [userId],\n )\n return rows.map(mapRole)\n }\n\n async assignRole(userId: string, roleId: string, tenantId = 'default'): Promise<void> {\n await this.exec('INSERT IGNORE INTO user_roles (user_id, role_id, tenant_id) VALUES (?,?,?)', [userId, roleId, tenantId])\n }\n\n async revokeRole(userId: string, roleId: string, tenantId?: string): Promise<void> {\n if (tenantId) {\n await this.exec('DELETE FROM user_roles WHERE user_id=? AND role_id=? AND tenant_id=?', [userId, roleId, tenantId])\n } else {\n await this.exec('DELETE FROM user_roles WHERE user_id=? AND role_id=?', [userId, roleId])\n }\n }\n\n async assignPermissionToRole(roleId: string, permissionId: string): Promise<void> {\n await this.exec('INSERT IGNORE INTO role_permissions (role_id, permission_id) VALUES (?,?)', [roleId, permissionId])\n }\n\n async revokePermissionFromRole(roleId: string, permissionId: string): Promise<void> {\n await this.exec('DELETE FROM role_permissions WHERE role_id=? AND permission_id=?', [roleId, permissionId])\n }\n\n // ── Audit logs ────────────────────────────────────────────────────────────────\n\n async createLog(data: CreateAuditLogInput): Promise<void> {\n await this.exec(\n 'INSERT INTO audit_logs (id, tenant_id, user_id, action, resource_type, resource_id, old_data, new_data) VALUES (?,?,?,?,?,?,?,?)',\n [randomUUID(), data.tenantId, data.userId ?? null, data.action, data.resourceType,\n data.resourceId ?? null,\n data.oldData != null ? JSON.stringify(data.oldData) : null,\n data.newData != null ? JSON.stringify(data.newData) : null],\n )\n }\n\n async getLogs(filters: AuditFilters): Promise<AuditLog[]> {\n const { sql, params } = this.buildAuditQuery(filters)\n const page = filters.page ?? 1\n const limit = filters.limit ?? 50\n const rows = await this.q<RowAuditLog>(`${sql} ORDER BY created_at DESC LIMIT ? OFFSET ?`, [...params, limit, (page - 1) * limit])\n return rows.map(mapAuditLog)\n }\n\n async *streamAuditLogs(filters: AuditFilters): AsyncIterable<AuditLog> {\n const { sql, params } = this.buildAuditQuery(filters)\n const rows = await this.q<RowAuditLog>(`${sql} ORDER BY created_at ASC`, params)\n for (const r of rows) yield mapAuditLog(r)\n }\n\n private buildAuditQuery(f: AuditFilters): { sql: string; params: (string | number | boolean | null)[] } {\n let sql = 'SELECT * FROM audit_logs WHERE tenant_id=?'\n const params: (string | number | boolean | null)[] = [f.tenantId]\n if (f.action != null) { sql += ' AND action=?'; params.push(f.action) }\n if (f.resourceType != null) { sql += ' AND resource_type=?'; params.push(f.resourceType) }\n if (f.from != null) { sql += ' AND created_at>=?'; params.push(f.from) }\n if (f.to != null) { sql += ' AND created_at<=?'; params.push(f.to) }\n return { sql, params }\n }\n\n // ── Stats extensions ───────────────────────────────────────────────────────────\n\n async getCountries(tenantId: string): Promise<CountryStat[]> {\n const rows = await this.q<RowCountry>(\n `SELECT v.country, COUNT(*) AS count FROM consent_records cr\n JOIN visitors v ON v.visitor_id=cr.visitor_id\n WHERE cr.tenant_id=? AND v.country IS NOT NULL\n GROUP BY v.country ORDER BY count DESC LIMIT 50`,\n [tenantId],\n )\n return rows.map(r => ({ country: r.country, count: r.count }))\n }\n\n async getGpcStats(tenantId: string): Promise<GpcStats> {\n const [t] = await this.q<RowCount>('SELECT COUNT(*) AS total FROM consent_records WHERE tenant_id=?', [tenantId])\n const [d] = await this.q<RowCount>('SELECT COUNT(*) AS total FROM consent_records WHERE tenant_id=? AND gpc_detected=1', [tenantId])\n const total = t?.total ?? 0\n const detected = d?.total ?? 0\n return { detected, total, rate: total > 0 ? Math.round((detected / total) * 100) : 0 }\n }\n\n // ── Tenants ───────────────────────────────────────────────────────────────────\n\n async getTenants(): Promise<Tenant[]> {\n const rows = await this.q<RowTenant>('SELECT * FROM tenants ORDER BY name ASC', [])\n return rows.map(r => ({ id: r.id, name: r.name, slug: r.slug, createdAt: r.created_at, updatedAt: r.updated_at }))\n }\n\n // ── API Keys ──────────────────────────────────────────────────────────────────\n\n async createApiKey(data: CreateApiKeyInput): Promise<ApiKey> {\n const id = randomUUID()\n await this.exec(\n 'INSERT INTO api_keys (id, tenant_id, key_hash, name) VALUES (?,?,?,?)',\n [id, data.tenantId, data.keyHash, data.name],\n )\n const rows = await this.q<RowApiKey>('SELECT * FROM api_keys WHERE id=?', [id])\n const r = rows[0]\n if (!r) throw new Error('Failed to create API key')\n return { id: r.id, tenantId: r.tenant_id, keyHash: r.key_hash, name: r.name, isActive: r.is_active === 1, createdAt: r.created_at }\n }\n\n async getApiKeyByHash(keyHash: string): Promise<ApiKey | null> {\n const rows = await this.q<RowApiKey>('SELECT * FROM api_keys WHERE key_hash=? AND is_active=1', [keyHash])\n const r = rows[0]\n if (!r) return null\n return { id: r.id, tenantId: r.tenant_id, keyHash: r.key_hash, name: r.name, isActive: r.is_active === 1, createdAt: r.created_at }\n }\n\n async revokeApiKey(id: string): Promise<void> {\n await this.exec('UPDATE api_keys SET is_active=0 WHERE id=?', [id])\n }\n\n async getApiKeys(tenantId: string): Promise<ApiKey[]> {\n const rows = await this.q<RowApiKey>('SELECT * FROM api_keys WHERE tenant_id=? ORDER BY created_at DESC', [tenantId])\n return rows.map(r => ({ id: r.id, tenantId: r.tenant_id, keyHash: r.key_hash, name: r.name, isActive: r.is_active === 1, createdAt: r.created_at }))\n }\n\n async createTenant(data: CreateTenantInput): Promise<Tenant> {\n const id = randomUUID()\n const now = new Date().toISOString()\n await this.exec('INSERT INTO tenants (id, name, slug, created_at, updated_at) VALUES (?,?,?,?,?)', [id, data.name, data.slug, now, now])\n const rows = await this.q<RowTenant>('SELECT * FROM tenants WHERE id=?', [id])\n const r = rows[0]\n if (!r) throw new Error('Failed to create tenant')\n return { id: r.id, name: r.name, slug: r.slug, createdAt: r.created_at, updatedAt: r.updated_at }\n }\n\n async updateTenant(id: string, data: UpdateTenantInput): Promise<Tenant> {\n const now = new Date().toISOString()\n const sets: string[] = ['updated_at=?']\n const vals: (string | number)[] = [now]\n if (data.name != null) { sets.push('name=?'); vals.push(data.name) }\n if (data.slug != null) { sets.push('slug=?'); vals.push(data.slug) }\n vals.push(id)\n await this.exec(`UPDATE tenants SET ${sets.join(',')} WHERE id=?`, vals)\n const rows = await this.q<RowTenant>('SELECT * FROM tenants WHERE id=?', [id])\n const r = rows[0]\n if (!r) throw new Error(`Tenant ${id} not found`)\n return { id: r.id, name: r.name, slug: r.slug, createdAt: r.created_at, updatedAt: r.updated_at }\n }\n\n async deleteTenant(id: string): Promise<void> {\n await this.exec('DELETE FROM tenants WHERE id=?', [id])\n }\n\n async purgeExpiredConsents(olderThanDays: number): Promise<number> {\n const cutoff = new Date(Date.now() - olderThanDays * 86_400_000).toISOString()\n const visitorRows = await this.q<{ visitor_id: string } & RowDataPacket>(\n 'SELECT visitor_id FROM consent_records WHERE created_at < ?', [cutoff]\n )\n if (visitorRows.length === 0) return 0\n const ids = visitorRows.map(r => r.visitor_id)\n const placeholders = ids.map(() => '?').join(',')\n await this.exec(`DELETE FROM consent_history WHERE visitor_id IN (${placeholders})`, ids)\n await this.exec(`DELETE FROM consent_records WHERE visitor_id IN (${placeholders})`, ids)\n return ids.length\n }\n\n // Template methods — not yet implemented for MySQL adapter\n async createCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async updateCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async deleteCookieTemplate(): Promise<void> { throw new Error('Not implemented') }\n async getCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async getCookieTemplates(): Promise<never> { throw new Error('Not implemented') }\n async copyCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async createUITemplate(): Promise<never> { throw new Error('Not implemented') }\n async updateUITemplate(): Promise<never> { throw new Error('Not implemented') }\n async deleteUITemplate(): Promise<void> { throw new Error('Not implemented') }\n async getUITemplate(): Promise<never> { throw new Error('Not implemented') }\n async getUITemplates(): Promise<never> { throw new Error('Not implemented') }\n async copyUITemplate(): Promise<never> { throw new Error('Not implemented') }\n}\n","import type { Pool, PoolClient, QueryResult } from 'pg'\nimport { randomUUID } from '../../utils/crypto'\nimport { SEED_TENANT, SEED_PERMISSIONS, SEED_ROLES, SEED_ROLE_PERMISSIONS, SCHEMA_SQL_POSTGRES } from '../seed-data'\nimport type {\n StorageAdapter, StorageConfig, Profile, ProfileConfig,\n CreateProfileInput, UpdateProfileInput,\n ConsentDbRecord, ConsentHistoryEntry, ConsentValue, ConsentFilters,\n CreateConsentInput, UpdateConsentInput,\n Visitor, VisitorFilters, CreateVisitorInput, UpdateVisitorInput,\n AdminUser, CreateUserInput, UpdateUserInput,\n Role, CreateRoleInput, UpdateRoleInput,\n Permission, AuditLog, AuditFilters, CreateAuditLogInput,\n OverviewStats, CategoryStats, TimelineEntry,\n CountryStat, GpcStats, Tenant, ApiKey, CreateApiKeyInput,\n CreateTenantInput, UpdateTenantInput,\n} from '@consenti/types'\n\n// ── Raw row shapes ─────────────────────────────────────────────────────────────\n\ninterface RowProfile {\n id: string; tenant_id: string; name: string; default_locale: string\n version: number; profile_json: string\n created_at: string; updated_at: string\n}\ninterface RowConsent {\n id: string; tenant_id: string; visitor_id: string; profile_id: string\n profile_version: number; locale: string; consent_json: string\n gpc_detected: boolean; source: string; created_at: string; updated_at: string\n age_verified?: boolean; parental_consent_token?: string | null; tcf_string?: string | null\n}\ninterface RowConsentHistory {\n id: string; tenant_id: string; consent_record_id: string; visitor_id: string\n old_json: string | null; new_json: string; action: string; created_at: string\n}\ninterface RowVisitor {\n id: string; tenant_id: string; visitor_id: string\n country: string | null; region: string | null; city: string | null\n ip_hash: string | null; user_agent_hash: string | null\n first_seen: string; last_seen: string\n}\ninterface RowUser {\n id: string; tenant_id: string; name: string; email: string\n password_hash: string; is_active: boolean; created_at: string; updated_at: string\n totp_secret?: string | null; totp_enabled?: boolean\n}\ninterface RowRole { id: string; tenant_id: string; name: string; description: string | null }\ninterface RowPermission { id: string; name: string; description: string | null }\ninterface RowAuditLog {\n id: string; tenant_id: string; user_id: string | null; action: string\n resource_type: string; resource_id: string | null\n old_data: string | null; new_data: string | null; created_at: string\n}\ninterface RowCount { total: string }\ninterface RowStatus { status: string; count: string }\ninterface RowDateCount { date: string; count: string }\ninterface RowCookieStatus { cookie_id: string; status: string; count: string }\ninterface RowCountry { country: string; count: string }\ninterface RowApiKey { id: string; tenant_id: string; key_hash: string; name: string; is_active: boolean; created_at: string }\ninterface RowTenant { id: string; name: string; slug: string; created_at: string; updated_at: string }\n\n// ── Mappers ────────────────────────────────────────────────────────────────────\n\nfunction mapProfile(r: RowProfile): Profile {\n return {\n id: r.id, tenantId: r.tenant_id, name: r.name,\n defaultLocale: r.default_locale, version: r.version,\n profileJson: JSON.parse(r.profile_json) as ProfileConfig,\n createdAt: r.created_at, updatedAt: r.updated_at,\n }\n}\n\nfunction mapConsent(r: RowConsent): ConsentDbRecord {\n return {\n id: r.id, tenantId: r.tenant_id, visitorId: r.visitor_id, profileId: r.profile_id,\n profileVersion: r.profile_version, locale: r.locale,\n consentJson: JSON.parse(r.consent_json) as ConsentValue,\n gpcDetected: r.gpc_detected, source: r.source as ConsentDbRecord['source'],\n createdAt: r.created_at, updatedAt: r.updated_at,\n ...(r.age_verified != null ? { ageVerified: r.age_verified } : {}),\n ...(r.parental_consent_token != null ? { parentalConsentToken: r.parental_consent_token } : {}),\n ...(r.tcf_string != null ? { tcfString: r.tcf_string } : {}),\n }\n}\n\nfunction mapHistory(r: RowConsentHistory): ConsentHistoryEntry {\n return {\n id: r.id, tenantId: r.tenant_id, consentRecordId: r.consent_record_id,\n visitorId: r.visitor_id,\n oldJson: r.old_json ? JSON.parse(r.old_json) as ConsentValue : null,\n newJson: JSON.parse(r.new_json) as ConsentValue,\n action: r.action as ConsentHistoryEntry['action'], createdAt: r.created_at,\n }\n}\n\nfunction mapVisitor(r: RowVisitor): Visitor {\n return {\n id: r.id, tenantId: r.tenant_id, visitorId: r.visitor_id,\n ...(r.country != null ? { country: r.country } : {}),\n ...(r.region != null ? { region: r.region } : {}),\n ...(r.city != null ? { city: r.city } : {}),\n ...(r.ip_hash != null ? { ipHash: r.ip_hash } : {}),\n ...(r.user_agent_hash != null ? { userAgentHash: r.user_agent_hash } : {}),\n firstSeen: r.first_seen, lastSeen: r.last_seen,\n }\n}\n\nfunction mapUser(r: RowUser): AdminUser {\n return {\n id: r.id, tenantId: r.tenant_id, name: r.name, email: r.email,\n passwordHash: r.password_hash, isActive: r.is_active,\n createdAt: r.created_at, updatedAt: r.updated_at,\n totpEnabled: r.totp_enabled ?? false,\n ...(r.totp_secret != null ? { totpSecret: r.totp_secret } : {}),\n }\n}\n\nfunction mapRole(r: RowRole): Role {\n return {\n id: r.id, tenantId: r.tenant_id, name: r.name,\n ...(r.description != null ? { description: r.description } : {}),\n }\n}\n\nfunction mapPermission(r: RowPermission): Permission {\n return {\n id: r.id, name: r.name,\n ...(r.description != null ? { description: r.description } : {}),\n }\n}\n\nfunction mapAuditLog(r: RowAuditLog): AuditLog {\n return {\n id: r.id, tenantId: r.tenant_id, action: r.action, resourceType: r.resource_type,\n ...(r.user_id != null ? { userId: r.user_id } : {}),\n ...(r.resource_id != null ? { resourceId: r.resource_id } : {}),\n ...(r.old_data != null ? { oldData: JSON.parse(r.old_data) as unknown } : {}),\n ...(r.new_data != null ? { newData: JSON.parse(r.new_data) as unknown } : {}),\n createdAt: r.created_at,\n }\n}\n\n// ── Adapter ────────────────────────────────────────────────────────────────────\n\nexport class PostgreSQLAdapter implements StorageAdapter {\n private pool!: Pool\n\n constructor(private config: StorageConfig) {}\n\n private async q<T>(sql: string, params: (string | number | boolean | null)[] = []): Promise<T[]> {\n const result: QueryResult<T & object> = await this.pool.query<T & object>(sql, params as unknown[])\n return result.rows\n }\n\n async connect(): Promise<void> {\n type PgModule = { Pool: new (cfg: Record<string, unknown>) => Pool }\n const pg = (await import('pg')) as { default: PgModule }\n const PgPool = pg.default.Pool\n const cfg = this.config\n const poolCfg: Record<string, unknown> = cfg.uri\n ? { connectionString: cfg.uri }\n : {\n host: cfg.host ?? 'localhost',\n port: cfg.port ?? 5432,\n user: cfg.user ?? 'postgres',\n password: cfg.password ?? '',\n database: cfg.database ?? cfg.dbName ?? 'consenti',\n }\n this.pool = new PgPool(poolCfg)\n await this.migrate()\n }\n\n async disconnect(): Promise<void> {\n await this.pool.end()\n }\n\n async migrate(): Promise<void> {\n const client: PoolClient = await this.pool.connect()\n try {\n let version = 0\n try {\n const res = await client.query<{ version: number }>('SELECT version FROM schema_version ORDER BY version DESC LIMIT 1')\n version = res.rows[0]?.version ?? 0\n } catch {\n // schema_version doesn't exist — fresh install\n }\n\n if (version === 0) {\n await client.query('BEGIN')\n try {\n for (const stmt of SCHEMA_SQL_POSTGRES.split(';').map(s => s.trim()).filter(Boolean)) {\n await client.query(stmt)\n }\n await this.seedTx(client)\n await client.query('INSERT INTO schema_version (version) VALUES (2) ON CONFLICT DO NOTHING')\n await client.query('COMMIT')\n } catch (err) {\n await client.query('ROLLBACK')\n throw err\n }\n return\n }\n\n if (version < 2) {\n await client.query('BEGIN')\n try {\n const alters = [\n 'ALTER TABLE consent_records ADD COLUMN IF NOT EXISTS age_verified BOOLEAN NOT NULL DEFAULT FALSE',\n 'ALTER TABLE consent_records ADD COLUMN IF NOT EXISTS parental_consent_token TEXT',\n 'ALTER TABLE consent_records ADD COLUMN IF NOT EXISTS tcf_string TEXT',\n 'ALTER TABLE users ADD COLUMN IF NOT EXISTS totp_secret TEXT',\n 'ALTER TABLE users ADD COLUMN IF NOT EXISTS totp_enabled BOOLEAN NOT NULL DEFAULT FALSE',\n ]\n for (const stmt of alters) await client.query(stmt)\n await client.query('INSERT INTO schema_version (version) VALUES (2) ON CONFLICT DO NOTHING')\n await client.query('COMMIT')\n } catch (err) {\n await client.query('ROLLBACK')\n throw err\n }\n }\n\n if (version < 3) {\n await client.query('BEGIN')\n try {\n await client.query('ALTER TABLE user_roles ADD COLUMN IF NOT EXISTS tenant_id TEXT NOT NULL DEFAULT \\'default\\'')\n await client.query('INSERT INTO schema_version (version) VALUES (3) ON CONFLICT DO NOTHING')\n await client.query('COMMIT')\n } catch (err) {\n await client.query('ROLLBACK')\n throw err\n }\n }\n } finally {\n client.release()\n }\n }\n\n private async seedTx(client: PoolClient): Promise<void> {\n await client.query(\n 'INSERT INTO tenants (id, name, slug) VALUES ($1,$2,$3) ON CONFLICT DO NOTHING',\n [SEED_TENANT.id, SEED_TENANT.name, SEED_TENANT.slug],\n )\n for (const p of SEED_PERMISSIONS) {\n await client.query(\n 'INSERT INTO permissions (id, name, description) VALUES ($1,$2,$3) ON CONFLICT DO NOTHING',\n [p.id, p.name, p.description],\n )\n }\n for (const r of SEED_ROLES) {\n await client.query(\n 'INSERT INTO roles (id, tenant_id, name, description) VALUES ($1,$2,$3,$4) ON CONFLICT DO NOTHING',\n [r.id, r.tenantId, r.name, r.description],\n )\n }\n for (const { roleId, permissionId } of SEED_ROLE_PERMISSIONS) {\n await client.query(\n 'INSERT INTO role_permissions VALUES ($1,$2) ON CONFLICT DO NOTHING',\n [roleId, permissionId],\n )\n }\n }\n\n // ── Profiles ─────────────────────────────────────────────────────────────────\n\n async createProfile(data: CreateProfileInput): Promise<Profile> {\n const id = randomUUID()\n const rows = await this.q<RowProfile>(\n `INSERT INTO profiles (id, tenant_id, name, default_locale, profile_json)\n VALUES ($1,$2,$3,$4,$5::jsonb) RETURNING *`,\n [id, data.tenantId, data.name, data.defaultLocale, JSON.stringify(data.profileJson)],\n )\n const row = rows[0]\n if (!row) throw new Error('Profile creation failed')\n return mapProfile(row)\n }\n\n async updateProfile(id: string, data: UpdateProfileInput): Promise<Profile> {\n const sets: string[] = ['version = version + 1', 'updated_at = NOW()']\n const vals: (string | number | boolean | null)[] = []\n let idx = 1\n if (data.name != null) { sets.push(`name=$${idx++}`); vals.push(data.name) }\n if (data.defaultLocale != null){ sets.push(`default_locale=$${idx++}`);vals.push(data.defaultLocale) }\n if (data.profileJson != null) { sets.push(`profile_json=$${idx++}::jsonb`);vals.push(JSON.stringify(data.profileJson)) }\n vals.push(id)\n const rows = await this.q<RowProfile>(\n `UPDATE profiles SET ${sets.join(',')} WHERE id=$${idx} RETURNING *`,\n vals,\n )\n const row = rows[0]\n if (!row) throw new Error(`Profile ${id} not found`)\n return mapProfile(row)\n }\n\n async deleteProfile(id: string): Promise<void> {\n await this.q('DELETE FROM profiles WHERE id=$1', [id])\n }\n\n async getProfile(id: string): Promise<Profile | null> {\n const rows = await this.q<RowProfile>('SELECT * FROM profiles WHERE id=$1', [id])\n return rows[0] ? mapProfile(rows[0]) : null\n }\n\n async getProfiles(tenantId: string): Promise<Profile[]> {\n const rows = await this.q<RowProfile>('SELECT * FROM profiles WHERE tenant_id=$1 ORDER BY created_at DESC', [tenantId])\n return rows.map(mapProfile)\n }\n\n // ── Consents ─────────────────────────────────────────────────────────────────\n\n async createConsent(data: CreateConsentInput): Promise<ConsentDbRecord> {\n const id = randomUUID()\n const rows = await this.q<RowConsent>(\n `INSERT INTO consent_records (id, tenant_id, visitor_id, profile_id, profile_version, locale, consent_json, gpc_detected, source)\n VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8,$9) RETURNING *`,\n [id, data.tenantId, data.visitorId, data.profileId, data.profileVersion,\n data.locale, JSON.stringify(data.consentJson), data.gpcDetected, data.source],\n )\n const row = rows[0]\n if (!row) throw new Error('Consent creation failed')\n await this.writeHistory(id, data.tenantId, data.visitorId, null, data.consentJson, 'created')\n return mapConsent(row)\n }\n\n async updateConsent(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord> {\n const existing = await this.getConsent(visitorId)\n if (!existing) throw new Error(`Consent for visitor ${visitorId} not found`)\n const sets: string[] = ['consent_json=$1::jsonb', 'updated_at=NOW()']\n const vals: (string | number | boolean | null)[] = [JSON.stringify(data.consentJson)]\n let idx = 2\n if (data.locale != null) { sets.push(`locale=$${idx++}`); vals.push(data.locale) }\n if (data.gpcDetected != null) { sets.push(`gpc_detected=$${idx++}`); vals.push(data.gpcDetected) }\n vals.push(visitorId)\n const rows = await this.q<RowConsent>(\n `UPDATE consent_records SET ${sets.join(',')} WHERE visitor_id=$${idx} RETURNING *`,\n vals,\n )\n const row = rows[0]\n if (!row) throw new Error(`Consent for visitor ${visitorId} not found`)\n await this.writeHistory(row.id, row.tenant_id, visitorId, existing.consentJson, data.consentJson, 'updated')\n return mapConsent(row)\n }\n\n async deleteConsent(visitorId: string): Promise<void> {\n await this.q('DELETE FROM consent_history WHERE visitor_id=$1', [visitorId])\n await this.q('DELETE FROM consent_records WHERE visitor_id=$1', [visitorId])\n }\n\n async getConsent(visitorId: string): Promise<ConsentDbRecord | null> {\n const rows = await this.q<RowConsent>('SELECT * FROM consent_records WHERE visitor_id=$1', [visitorId])\n return rows[0] ? mapConsent(rows[0]) : null\n }\n\n async getConsents(filters: ConsentFilters): Promise<ConsentDbRecord[]> {\n const { sql, params, nextIdx } = this.buildConsentQuery(filters)\n const page = filters.page ?? 1\n const limit = filters.limit ?? 50\n const rows = await this.q<RowConsent>(\n `${sql} ORDER BY created_at DESC LIMIT $${nextIdx} OFFSET $${nextIdx + 1}`,\n [...params, limit, (page - 1) * limit],\n )\n return rows.map(mapConsent)\n }\n\n async *streamConsents(filters: ConsentFilters): AsyncIterable<ConsentDbRecord> {\n const { sql, params } = this.buildConsentQuery(filters)\n const rows = await this.q<RowConsent>(`${sql} ORDER BY created_at ASC`, params)\n for (const r of rows) yield mapConsent(r)\n }\n\n private buildConsentQuery(f: ConsentFilters): { sql: string; params: (string | number | boolean | null)[]; nextIdx: number } {\n let sql = 'SELECT * FROM consent_records WHERE tenant_id=$1'\n const params: (string | number | boolean | null)[] = [f.tenantId]\n let idx = 2\n if (f.profileId != null) { sql += ` AND profile_id=$${idx++}`; params.push(f.profileId) }\n if (f.from != null) { sql += ` AND created_at>=$${idx++}`; params.push(f.from) }\n if (f.to != null) { sql += ` AND created_at<=$${idx++}`; params.push(f.to) }\n return { sql, params, nextIdx: idx }\n }\n\n private async writeHistory(\n consentRecordId: string, tenantId: string, visitorId: string,\n oldJson: ConsentValue | null, newJson: ConsentValue, action: string,\n ): Promise<void> {\n await this.q(\n `INSERT INTO consent_history (id, tenant_id, consent_record_id, visitor_id, old_json, new_json, action)\n VALUES ($1,$2,$3,$4,$5::jsonb,$6::jsonb,$7)`,\n [randomUUID(), tenantId, consentRecordId, visitorId,\n oldJson ? JSON.stringify(oldJson) : null, JSON.stringify(newJson), action],\n )\n }\n\n async getConsentHistory(visitorId: string): Promise<ConsentHistoryEntry[]> {\n const rows = await this.q<RowConsentHistory>(\n 'SELECT * FROM consent_history WHERE visitor_id=$1 ORDER BY created_at ASC',\n [visitorId],\n )\n return rows.map(mapHistory)\n }\n\n // ── Visitors ─────────────────────────────────────────────────────────────────\n\n async createVisitor(data: CreateVisitorInput): Promise<Visitor> {\n const id = randomUUID()\n const rows = await this.q<RowVisitor>(\n `INSERT INTO visitors (id, tenant_id, visitor_id, country, region, city, ip_hash, user_agent_hash)\n VALUES ($1,$2,$3,$4,$5,$6,$7,$8) RETURNING *`,\n [id, data.tenantId, data.visitorId,\n data.country ?? null, data.region ?? null, data.city ?? null,\n data.ipHash ?? null, data.userAgentHash ?? null],\n )\n const row = rows[0]\n if (!row) throw new Error('Visitor creation failed')\n return mapVisitor(row)\n }\n\n async updateVisitor(visitorId: string, data: UpdateVisitorInput): Promise<Visitor> {\n const sets: string[] = ['last_seen=NOW()']\n const vals: (string | number | boolean | null)[] = []\n let idx = 1\n if (data.country != null) { sets.push(`country=$${idx++}`); vals.push(data.country) }\n if (data.region != null) { sets.push(`region=$${idx++}`); vals.push(data.region) }\n if (data.city != null) { sets.push(`city=$${idx++}`); vals.push(data.city) }\n vals.push(visitorId)\n const rows = await this.q<RowVisitor>(\n `UPDATE visitors SET ${sets.join(',')} WHERE visitor_id=$${idx} RETURNING *`,\n vals,\n )\n const row = rows[0]\n if (!row) throw new Error(`Visitor ${visitorId} not found`)\n return mapVisitor(row)\n }\n\n async deleteVisitor(visitorId: string): Promise<void> {\n await this.q('DELETE FROM visitors WHERE visitor_id=$1', [visitorId])\n }\n\n async getVisitor(visitorId: string): Promise<Visitor | null> {\n const rows = await this.q<RowVisitor>('SELECT * FROM visitors WHERE visitor_id=$1', [visitorId])\n return rows[0] ? mapVisitor(rows[0]) : null\n }\n\n async getVisitors(filters: VisitorFilters): Promise<Visitor[]> {\n let sql = 'SELECT * FROM visitors WHERE tenant_id=$1'\n const params: (string | number | boolean | null)[] = [filters.tenantId]\n let idx = 2\n if (filters.from != null) { sql += ` AND first_seen>=$${idx++}`; params.push(filters.from) }\n if (filters.to != null) { sql += ` AND first_seen<=$${idx++}`; params.push(filters.to) }\n const page = filters.page ?? 1\n const limit = filters.limit ?? 50\n const rows = await this.q<RowVisitor>(\n `${sql} ORDER BY first_seen DESC LIMIT $${idx} OFFSET $${idx + 1}`,\n [...params, limit, (page - 1) * limit],\n )\n return rows.map(mapVisitor)\n }\n\n // ── Stats ─────────────────────────────────────────────────────────────────────\n\n async getOverviewStats(tenantId: string): Promise<OverviewStats> {\n const [[countRow], [gpcRow], [visitorRow]] = await Promise.all([\n this.q<RowCount>('SELECT COUNT(*)::int AS total FROM consent_records WHERE tenant_id=$1', [tenantId]),\n this.q<RowCount>('SELECT COUNT(*)::int AS total FROM consent_records WHERE tenant_id=$1 AND gpc_detected=true', [tenantId]),\n this.q<RowCount>('SELECT COUNT(*)::int AS total FROM visitors WHERE tenant_id=$1', [tenantId]),\n ])\n const total = Number(countRow?.total ?? 0)\n const gpcCount = Number(gpcRow?.total ?? 0)\n const visitors = Number(visitorRow?.total ?? 0)\n\n const statusRows = await this.q<RowStatus>(\n `SELECT val AS status, COUNT(*)::int AS count\n FROM consent_records cr,\n jsonb_each_text(cr.consent_json) AS kv(key, val)\n WHERE cr.tenant_id=$1\n GROUP BY val`,\n [tenantId],\n )\n let granted = 0, denied = 0, all = 0\n for (const r of statusRows) {\n all += Number(r.count)\n if (r.status === 'granted') granted = Number(r.count)\n if (r.status === 'denied') denied = Number(r.count)\n }\n return {\n totalConsents: total,\n acceptedPct: all > 0 ? Math.round((granted / all) * 100) : 0,\n rejectedPct: all > 0 ? Math.round((denied / all) * 100) : 0,\n totalVisitors: visitors,\n gpcDetectedCount: gpcCount,\n }\n }\n\n async getCategoryStats(tenantId: string): Promise<CategoryStats> {\n const rows = await this.q<RowCookieStatus>(\n `SELECT kv.key AS cookie_id, kv.val AS status, COUNT(*)::int AS count\n FROM consent_records cr,\n jsonb_each_text(cr.consent_json) AS kv(key, val)\n WHERE cr.tenant_id=$1\n GROUP BY kv.key, kv.val`,\n [tenantId],\n )\n const result: CategoryStats = {}\n for (const r of rows) {\n if (!result[r.cookie_id]) result[r.cookie_id] = { granted: 0, denied: 0, objected: 0 }\n const entry = result[r.cookie_id]\n if (entry) {\n if (r.status === 'granted') entry.granted += Number(r.count)\n if (r.status === 'denied') entry.denied += Number(r.count)\n if (r.status === 'objected') entry.objected += Number(r.count)\n }\n }\n return result\n }\n\n async getTimeline(tenantId: string, days = 30): Promise<TimelineEntry[]> {\n const from = new Date(Date.now() - days * 86400_000).toISOString()\n const rows = await this.q<RowDateCount>(\n `SELECT to_char(created_at, 'YYYY-MM-DD') AS date, COUNT(*)::int AS count\n FROM consent_records\n WHERE tenant_id=$1 AND created_at>=$2\n GROUP BY to_char(created_at, 'YYYY-MM-DD')\n ORDER BY date ASC`,\n [tenantId, from],\n )\n return rows.map(r => ({ date: r.date, count: Number(r.count) }))\n }\n\n // ── Users ─────────────────────────────────────────────────────────────────────\n\n async createUser(data: CreateUserInput): Promise<AdminUser> {\n const id = randomUUID()\n const rows = await this.q<RowUser>(\n 'INSERT INTO users (id, tenant_id, name, email, password_hash) VALUES ($1,$2,$3,$4,$5) RETURNING *',\n [id, data.tenantId, data.name, data.email, data.passwordHash],\n )\n const row = rows[0]\n if (!row) throw new Error('User creation failed')\n return mapUser(row)\n }\n\n async updateUser(id: string, data: UpdateUserInput): Promise<AdminUser> {\n const sets: string[] = ['updated_at=NOW()']\n const vals: (string | number | boolean | null)[] = []\n let idx = 1\n if (data.name != null) { sets.push(`name=$${idx++}`); vals.push(data.name) }\n if (data.email != null) { sets.push(`email=$${idx++}`); vals.push(data.email) }\n if (data.passwordHash != null) { sets.push(`password_hash=$${idx++}`); vals.push(data.passwordHash) }\n if (data.isActive != null) { sets.push(`is_active=$${idx++}`); vals.push(data.isActive) }\n vals.push(id)\n const rows = await this.q<RowUser>(\n `UPDATE users SET ${sets.join(',')} WHERE id=$${idx} RETURNING *`,\n vals,\n )\n const row = rows[0]\n if (!row) throw new Error(`User ${id} not found`)\n return mapUser(row)\n }\n\n async deleteUser(id: string): Promise<void> {\n await this.q('DELETE FROM user_roles WHERE user_id=$1', [id])\n await this.q('DELETE FROM users WHERE id=$1', [id])\n }\n\n async getUserById(id: string): Promise<AdminUser | null> {\n const rows = await this.q<RowUser>('SELECT * FROM users WHERE id=$1', [id])\n return rows[0] ? mapUser(rows[0]) : null\n }\n\n async getUserByEmail(email: string): Promise<AdminUser | null> {\n const rows = await this.q<RowUser>('SELECT * FROM users WHERE email=$1', [email])\n return rows[0] ? mapUser(rows[0]) : null\n }\n\n async getUsers(tenantId: string): Promise<AdminUser[]> {\n const rows = await this.q<RowUser>('SELECT * FROM users WHERE tenant_id=$1 ORDER BY created_at DESC', [tenantId])\n return rows.map(mapUser)\n }\n\n async countUsers(tenantId?: string): Promise<number> {\n const rows = tenantId\n ? await this.q<RowCount>('SELECT COUNT(*)::int AS total FROM users WHERE tenant_id=$1', [tenantId])\n : await this.q<RowCount>('SELECT COUNT(*)::int AS total FROM users')\n return Number(rows[0]?.total ?? 0)\n }\n\n // ── Roles & permissions ───────────────────────────────────────────────────────\n\n async getRoles(tenantId: string): Promise<Role[]> {\n const rows = await this.q<RowRole>('SELECT * FROM roles WHERE tenant_id=$1', [tenantId])\n return rows.map(mapRole)\n }\n\n async createRole(data: CreateRoleInput): Promise<Role> {\n const id = randomUUID()\n const rows = await this.q<RowRole>(\n 'INSERT INTO roles (id, tenant_id, name, description) VALUES ($1,$2,$3,$4) RETURNING *',\n [id, data.tenantId, data.name, data.description ?? null],\n )\n const row = rows[0]\n if (!row) throw new Error('Role creation failed')\n return mapRole(row)\n }\n\n async updateRole(id: string, data: UpdateRoleInput): Promise<Role> {\n const sets: string[] = []\n const vals: (string | number | boolean | null)[] = []\n let idx = 1\n if (data.name != null) { sets.push(`name=$${idx++}`); vals.push(data.name) }\n if (data.description != null) { sets.push(`description=$${idx++}`); vals.push(data.description) }\n if (sets.length === 0) {\n const rows = await this.q<RowRole>('SELECT * FROM roles WHERE id=$1', [id])\n const row = rows[0]\n if (!row) throw new Error(`Role ${id} not found`)\n return mapRole(row)\n }\n vals.push(id)\n const rows = await this.q<RowRole>(`UPDATE roles SET ${sets.join(',')} WHERE id=$${idx} RETURNING *`, vals)\n const row = rows[0]\n if (!row) throw new Error(`Role ${id} not found`)\n return mapRole(row)\n }\n\n async deleteRole(id: string): Promise<void> {\n await this.q('DELETE FROM role_permissions WHERE role_id=$1', [id])\n await this.q('DELETE FROM user_roles WHERE role_id=$1', [id])\n await this.q('DELETE FROM roles WHERE id=$1', [id])\n }\n\n async getAllPermissions(): Promise<Permission[]> {\n const rows = await this.q<RowPermission>('SELECT * FROM permissions ORDER BY name')\n return rows.map(mapPermission)\n }\n\n async getPermissionsForRole(roleId: string): Promise<Permission[]> {\n const rows = await this.q<RowPermission>(\n 'SELECT p.* FROM permissions p JOIN role_permissions rp ON p.id=rp.permission_id WHERE rp.role_id=$1',\n [roleId],\n )\n return rows.map(mapPermission)\n }\n\n async getUserRoles(userId: string, tenantId?: string): Promise<Role[]> {\n const rows = tenantId\n ? await this.q<RowRole>(\n 'SELECT r.* FROM roles r JOIN user_roles ur ON r.id=ur.role_id WHERE ur.user_id=$1 AND ur.tenant_id=$2',\n [userId, tenantId],\n )\n : await this.q<RowRole>(\n 'SELECT r.* FROM roles r JOIN user_roles ur ON r.id=ur.role_id WHERE ur.user_id=$1',\n [userId],\n )\n return rows.map(mapRole)\n }\n\n async assignRole(userId: string, roleId: string, tenantId = 'default'): Promise<void> {\n await this.q('INSERT INTO user_roles (user_id, role_id, tenant_id) VALUES ($1,$2,$3) ON CONFLICT DO NOTHING', [userId, roleId, tenantId])\n }\n\n async revokeRole(userId: string, roleId: string, tenantId?: string): Promise<void> {\n if (tenantId) {\n await this.q('DELETE FROM user_roles WHERE user_id=$1 AND role_id=$2 AND tenant_id=$3', [userId, roleId, tenantId])\n } else {\n await this.q('DELETE FROM user_roles WHERE user_id=$1 AND role_id=$2', [userId, roleId])\n }\n }\n\n async assignPermissionToRole(roleId: string, permissionId: string): Promise<void> {\n await this.q('INSERT INTO role_permissions (role_id, permission_id) VALUES ($1,$2) ON CONFLICT DO NOTHING', [roleId, permissionId])\n }\n\n async revokePermissionFromRole(roleId: string, permissionId: string): Promise<void> {\n await this.q('DELETE FROM role_permissions WHERE role_id=$1 AND permission_id=$2', [roleId, permissionId])\n }\n\n // ── Audit logs ────────────────────────────────────────────────────────────────\n\n async createLog(data: CreateAuditLogInput): Promise<void> {\n await this.q(\n `INSERT INTO audit_logs (id, tenant_id, user_id, action, resource_type, resource_id, old_data, new_data)\n VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8::jsonb)`,\n [randomUUID(), data.tenantId, data.userId ?? null, data.action, data.resourceType,\n data.resourceId ?? null,\n data.oldData != null ? JSON.stringify(data.oldData) : null,\n data.newData != null ? JSON.stringify(data.newData) : null],\n )\n }\n\n async getLogs(filters: AuditFilters): Promise<AuditLog[]> {\n const { sql, params, nextIdx } = this.buildAuditQuery(filters)\n const page = filters.page ?? 1\n const limit = filters.limit ?? 50\n const rows = await this.q<RowAuditLog>(\n `${sql} ORDER BY created_at DESC LIMIT $${nextIdx} OFFSET $${nextIdx + 1}`,\n [...params, limit, (page - 1) * limit],\n )\n return rows.map(mapAuditLog)\n }\n\n async *streamAuditLogs(filters: AuditFilters): AsyncIterable<AuditLog> {\n const { sql, params } = this.buildAuditQuery(filters)\n const rows = await this.q<RowAuditLog>(`${sql} ORDER BY created_at ASC`, params)\n for (const r of rows) yield mapAuditLog(r)\n }\n\n private buildAuditQuery(f: AuditFilters): { sql: string; params: (string | number | boolean | null)[]; nextIdx: number } {\n let sql = 'SELECT * FROM audit_logs WHERE tenant_id=$1'\n const params: (string | number | boolean | null)[] = [f.tenantId]\n let idx = 2\n if (f.action != null) { sql += ` AND action=$${idx++}`; params.push(f.action) }\n if (f.resourceType != null) { sql += ` AND resource_type=$${idx++}`; params.push(f.resourceType) }\n if (f.from != null) { sql += ` AND created_at>=$${idx++}`; params.push(f.from) }\n if (f.to != null) { sql += ` AND created_at<=$${idx++}`; params.push(f.to) }\n return { sql, params, nextIdx: idx }\n }\n\n // ── Stats extensions ───────────────────────────────────────────────────────────\n\n async getCountries(tenantId: string): Promise<CountryStat[]> {\n const rows = await this.q<RowCountry>(\n `SELECT v.country, COUNT(*)::int AS count FROM consent_records cr\n JOIN visitors v ON v.visitor_id=cr.visitor_id\n WHERE cr.tenant_id=$1 AND v.country IS NOT NULL\n GROUP BY v.country ORDER BY count DESC LIMIT 50`,\n [tenantId],\n )\n return rows.map(r => ({ country: r.country, count: Number(r.count) }))\n }\n\n async getGpcStats(tenantId: string): Promise<GpcStats> {\n const [t] = await this.q<RowCount>('SELECT COUNT(*)::int AS total FROM consent_records WHERE tenant_id=$1', [tenantId])\n const [d] = await this.q<RowCount>('SELECT COUNT(*)::int AS total FROM consent_records WHERE tenant_id=$1 AND gpc_detected=TRUE', [tenantId])\n const total = Number(t?.total ?? 0)\n const detected = Number(d?.total ?? 0)\n return { detected, total, rate: total > 0 ? Math.round((detected / total) * 100) : 0 }\n }\n\n // ── Tenants ───────────────────────────────────────────────────────────────────\n\n async getTenants(): Promise<Tenant[]> {\n const rows = await this.q<RowTenant>('SELECT * FROM tenants ORDER BY name ASC', [])\n return rows.map(r => ({ id: r.id, name: r.name, slug: r.slug, createdAt: r.created_at, updatedAt: r.updated_at }))\n }\n\n // ── API Keys ──────────────────────────────────────────────────────────────────\n\n async createApiKey(data: CreateApiKeyInput): Promise<ApiKey> {\n const id = randomUUID()\n const rows = await this.q<RowApiKey>(\n 'INSERT INTO api_keys (id, tenant_id, key_hash, name) VALUES ($1,$2,$3,$4) RETURNING *',\n [id, data.tenantId, data.keyHash, data.name],\n )\n const r = rows[0]\n if (!r) throw new Error('Failed to create API key')\n return { id: r.id, tenantId: r.tenant_id, keyHash: r.key_hash, name: r.name, isActive: r.is_active, createdAt: r.created_at }\n }\n\n async getApiKeyByHash(keyHash: string): Promise<ApiKey | null> {\n const rows = await this.q<RowApiKey>('SELECT * FROM api_keys WHERE key_hash=$1 AND is_active=TRUE', [keyHash])\n const r = rows[0]\n if (!r) return null\n return { id: r.id, tenantId: r.tenant_id, keyHash: r.key_hash, name: r.name, isActive: r.is_active, createdAt: r.created_at }\n }\n\n async revokeApiKey(id: string): Promise<void> {\n await this.q('UPDATE api_keys SET is_active=FALSE WHERE id=$1', [id])\n }\n\n async getApiKeys(tenantId: string): Promise<ApiKey[]> {\n const rows = await this.q<RowApiKey>('SELECT * FROM api_keys WHERE tenant_id=$1 ORDER BY created_at DESC', [tenantId])\n return rows.map(r => ({ id: r.id, tenantId: r.tenant_id, keyHash: r.key_hash, name: r.name, isActive: r.is_active, createdAt: r.created_at }))\n }\n\n async createTenant(data: CreateTenantInput): Promise<Tenant> {\n const id = randomUUID()\n const now = new Date().toISOString()\n const rows = await this.q<RowTenant>(\n 'INSERT INTO tenants (id, name, slug, created_at, updated_at) VALUES ($1,$2,$3,$4,$5) RETURNING *',\n [id, data.name, data.slug, now, now],\n )\n const r = rows[0]\n if (!r) throw new Error('Failed to create tenant')\n return { id: r.id, name: r.name, slug: r.slug, createdAt: r.created_at, updatedAt: r.updated_at }\n }\n\n async updateTenant(id: string, data: UpdateTenantInput): Promise<Tenant> {\n const now = new Date().toISOString()\n const sets: string[] = ['updated_at=$1']\n const vals: (string | number)[] = [now]\n let idx = 2\n if (data.name != null) { sets.push(`name=$${idx++}`); vals.push(data.name) }\n if (data.slug != null) { sets.push(`slug=$${idx++}`); vals.push(data.slug) }\n vals.push(id)\n const rows = await this.q<RowTenant>(\n `UPDATE tenants SET ${sets.join(',')} WHERE id=$${idx} RETURNING *`, vals,\n )\n const r = rows[0]\n if (!r) throw new Error(`Tenant ${id} not found`)\n return { id: r.id, name: r.name, slug: r.slug, createdAt: r.created_at, updatedAt: r.updated_at }\n }\n\n async deleteTenant(id: string): Promise<void> {\n await this.q('DELETE FROM tenants WHERE id=$1', [id])\n }\n\n async purgeExpiredConsents(olderThanDays: number): Promise<number> {\n const cutoff = new Date(Date.now() - olderThanDays * 86_400_000).toISOString()\n const visitorRows = await this.q<{ visitor_id: string }>(\n 'SELECT visitor_id FROM consent_records WHERE created_at < $1', [cutoff]\n )\n if (visitorRows.length === 0) return 0\n const ids = visitorRows.map(r => r.visitor_id)\n const placeholders = ids.map((_: string, i: number) => `$${i + 1}`).join(',')\n await this.q(`DELETE FROM consent_history WHERE visitor_id IN (${placeholders})`, ids)\n await this.q(`DELETE FROM consent_records WHERE visitor_id IN (${placeholders})`, ids)\n return ids.length\n }\n\n // Template methods — not yet implemented for PostgreSQL adapter\n async createCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async updateCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async deleteCookieTemplate(): Promise<void> { throw new Error('Not implemented') }\n async getCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async getCookieTemplates(): Promise<never> { throw new Error('Not implemented') }\n async copyCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async createUITemplate(): Promise<never> { throw new Error('Not implemented') }\n async updateUITemplate(): Promise<never> { throw new Error('Not implemented') }\n async deleteUITemplate(): Promise<void> { throw new Error('Not implemented') }\n async getUITemplate(): Promise<never> { throw new Error('Not implemented') }\n async getUITemplates(): Promise<never> { throw new Error('Not implemented') }\n async copyUITemplate(): Promise<never> { throw new Error('Not implemented') }\n}\n","import { readFile, writeFile, rename, mkdir } from 'node:fs/promises'\nimport { randomUUID } from 'node:crypto'\nimport { dirname } from 'node:path'\nimport type {\n StorageAdapter,\n StorageConfig,\n Profile,\n ProfileConfig,\n CreateProfileInput,\n UpdateProfileInput,\n ConsentDbRecord,\n ConsentHistoryEntry,\n ConsentValue,\n CreateConsentInput,\n UpdateConsentInput,\n ConsentFilters,\n Visitor,\n VisitorFilters,\n CreateVisitorInput,\n UpdateVisitorInput,\n AdminUser,\n CreateUserInput,\n UpdateUserInput,\n Role,\n CreateRoleInput,\n UpdateRoleInput,\n Permission,\n AuditLog,\n AuditFilters,\n CreateAuditLogInput,\n OverviewStats,\n CategoryStats,\n TimelineEntry,\n CountryStat,\n GpcStats,\n Tenant,\n ApiKey,\n CreateApiKeyInput,\n CreateTenantInput,\n UpdateTenantInput,\n ServerCookieTemplate,\n ServerUITemplate,\n CreateCookieTemplateInput,\n UpdateCookieTemplateInput,\n CreateUITemplateInput,\n UpdateUITemplateInput,\n} from '@consenti/types'\nimport {\n SEED_TENANT,\n SEED_PERMISSIONS,\n SEED_ROLES,\n SEED_ROLE_PERMISSIONS,\n} from '../seed-data'\n\nconst MAX_PAGE_SIZE = 500\n\ninterface UserRole { userId: string; roleId: string; tenantId: string }\ninterface RolePermission { roleId: string; permissionId: string }\n\ninterface JsonDb {\n _version: number\n tenants: Tenant[]\n profiles: Profile[]\n consents: ConsentDbRecord[]\n consent_history: ConsentHistoryEntry[]\n visitors: Visitor[]\n users: AdminUser[]\n roles: Role[]\n permissions: Permission[]\n user_roles: UserRole[]\n role_permissions: RolePermission[]\n audit_logs: AuditLog[]\n cookie_templates: ServerCookieTemplate[]\n ui_templates: ServerUITemplate[]\n api_keys: ApiKey[]\n}\n\nfunction emptyDb(): JsonDb {\n return {\n _version: 1,\n tenants: [],\n profiles: [],\n consents: [],\n consent_history: [],\n visitors: [],\n users: [],\n roles: [],\n permissions: [],\n user_roles: [],\n role_permissions: [],\n audit_logs: [],\n cookie_templates: [],\n ui_templates: [],\n api_keys: [],\n }\n}\n\nfunction randomProfileId(): string {\n return `prof_${randomUUID().replace(/-/g, '')}`\n}\n\nfunction page<T>(arr: T[], pageNum: number, limit: number): T[] {\n const l = Math.min(limit, MAX_PAGE_SIZE)\n const offset = (pageNum - 1) * l\n return arr.slice(offset, offset + l)\n}\n\nexport class JsonFileAdapter implements StorageAdapter {\n private db: JsonDb = emptyDb()\n private filePath: string\n // Steno-equivalent: serialised writes via promise chain.\n // Old settled promises are GC'd on reassignment — no memory leak.\n private writeQueue: Promise<void> = Promise.resolve()\n\n constructor(private config: StorageConfig) {\n this.filePath = config.path ?? './consenti-data.json'\n }\n\n private scheduleWrite(): void {\n this.writeQueue = this.writeQueue\n .then(async () => {\n await mkdir(dirname(this.filePath), { recursive: true })\n const tmp = `${this.filePath}.tmp`\n await writeFile(tmp, JSON.stringify(this.db), 'utf8')\n await rename(tmp, this.filePath)\n })\n .catch((err: unknown) => { console.warn('[Consenti] JSON store write failed:', err) })\n }\n\n async connect(): Promise<void> {\n try {\n const raw = await readFile(this.filePath, 'utf8')\n this.db = JSON.parse(raw) as JsonDb\n } catch {\n this.db = emptyDb()\n }\n await this.migrate()\n }\n\n async disconnect(): Promise<void> {\n await this.writeQueue\n }\n\n async migrate(): Promise<void> {\n this.seed()\n }\n\n private seed(): void {\n const now = new Date().toISOString()\n const { id, name, slug } = SEED_TENANT\n if (!this.db.tenants.find(t => t.id === id)) {\n this.db.tenants.push({ id, name, slug, createdAt: now, updatedAt: now })\n }\n for (const p of SEED_PERMISSIONS) {\n if (!this.db.permissions.find(x => x.id === p.id)) {\n this.db.permissions.push({ id: p.id, name: p.name, description: p.description })\n }\n }\n for (const r of SEED_ROLES) {\n if (!this.db.roles.find(x => x.id === r.id)) {\n this.db.roles.push({ id: r.id, tenantId: r.tenantId, name: r.name, description: r.description })\n }\n }\n for (const rp of SEED_ROLE_PERMISSIONS) {\n if (!this.db.role_permissions.find(x => x.roleId === rp.roleId && x.permissionId === rp.permissionId)) {\n this.db.role_permissions.push(rp)\n }\n }\n this.scheduleWrite()\n }\n\n // ── Profiles ──────────────────────────────────────────────────────────────\n\n async createProfile(data: CreateProfileInput): Promise<Profile> {\n const now = new Date().toISOString()\n const profile: Profile = {\n id: randomProfileId(),\n tenantId: data.tenantId,\n name: data.name,\n defaultLocale: data.defaultLocale,\n version: 1,\n profileJson: data.profileJson as ProfileConfig,\n createdAt: now,\n updatedAt: now,\n }\n this.db.profiles.push(profile)\n this.scheduleWrite()\n return profile\n }\n\n async updateProfile(id: string, data: UpdateProfileInput): Promise<Profile> {\n const idx = this.db.profiles.findIndex(p => p.id === id)\n if (idx === -1) throw new Error(`Profile ${id} not found`)\n const existing = this.db.profiles[idx]!\n const updated: Profile = {\n ...existing,\n ...(data.name != null && { name: data.name }),\n ...(data.defaultLocale != null && { defaultLocale: data.defaultLocale }),\n ...(data.profileJson != null && { profileJson: data.profileJson as ProfileConfig }),\n version: existing.version + 1,\n updatedAt: new Date().toISOString(),\n }\n this.db.profiles[idx] = updated\n this.scheduleWrite()\n return updated\n }\n\n async deleteProfile(id: string): Promise<void> {\n this.db.profiles = this.db.profiles.filter(p => p.id !== id)\n this.scheduleWrite()\n }\n\n async getProfile(id: string): Promise<Profile | null> {\n return this.db.profiles.find(p => p.id === id) ?? null\n }\n\n async getProfiles(tenantId: string): Promise<Profile[]> {\n return this.db.profiles.filter(p => p.tenantId === tenantId)\n .sort((a, b) => a.createdAt.localeCompare(b.createdAt))\n }\n\n // ── Consents ──────────────────────────────────────────────────────────────\n\n async createConsent(data: CreateConsentInput): Promise<ConsentDbRecord> {\n const now = new Date().toISOString()\n const id = randomUUID()\n const record: ConsentDbRecord = {\n id,\n tenantId: data.tenantId,\n visitorId: data.visitorId,\n profileId: data.profileId,\n profileVersion: data.profileVersion,\n locale: data.locale,\n consentJson: data.consentJson as ConsentValue,\n gpcDetected: data.gpcDetected ?? false,\n source: data.source as ConsentDbRecord['source'],\n createdAt: now,\n updatedAt: now,\n }\n this.db.consents.push(record)\n this.db.consent_history.push({\n id: randomUUID(),\n tenantId: data.tenantId,\n consentRecordId: id,\n visitorId: data.visitorId,\n oldJson: null,\n newJson: data.consentJson as ConsentValue,\n action: 'created',\n createdAt: now,\n })\n this.scheduleWrite()\n return record\n }\n\n async updateConsent(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord> {\n const idx = this.db.consents.findIndex(c => c.visitorId === visitorId)\n if (idx === -1) throw new Error(`Consent for visitor ${visitorId} not found`)\n const existing = this.db.consents[idx]!\n const now = new Date().toISOString()\n const updated: ConsentDbRecord = {\n ...existing,\n consentJson: data.consentJson as ConsentValue,\n ...(data.locale != null && { locale: data.locale }),\n ...(data.gpcDetected != null && { gpcDetected: data.gpcDetected }),\n updatedAt: now,\n }\n this.db.consents[idx] = updated\n this.db.consent_history.push({\n id: randomUUID(),\n tenantId: existing.tenantId,\n consentRecordId: existing.id,\n visitorId,\n oldJson: existing.consentJson,\n newJson: data.consentJson as ConsentValue,\n action: 'updated',\n createdAt: now,\n })\n this.scheduleWrite()\n return updated\n }\n\n async deleteConsent(visitorId: string): Promise<void> {\n this.db.consent_history = this.db.consent_history.filter(h => h.visitorId !== visitorId)\n this.db.consents = this.db.consents.filter(c => c.visitorId !== visitorId)\n this.scheduleWrite()\n }\n\n async getConsent(visitorId: string): Promise<ConsentDbRecord | null> {\n return this.db.consents.find(c => c.visitorId === visitorId) ?? null\n }\n\n async getConsents(filters: ConsentFilters): Promise<ConsentDbRecord[]> {\n let rows = this.db.consents.filter(c => c.tenantId === filters.tenantId)\n if (filters.profileId) rows = rows.filter(c => c.profileId === filters.profileId)\n if (filters.from) rows = rows.filter(c => c.createdAt >= filters.from!)\n if (filters.to) rows = rows.filter(c => c.createdAt <= filters.to!)\n rows.sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n return page(rows, filters.page ?? 1, filters.limit ?? 50)\n }\n\n async *streamConsents(filters: ConsentFilters): AsyncIterable<ConsentDbRecord> {\n for (const c of this.db.consents.filter(c => c.tenantId === filters.tenantId)) yield c\n }\n\n async getConsentHistory(visitorId: string): Promise<ConsentHistoryEntry[]> {\n return this.db.consent_history\n .filter(h => h.visitorId === visitorId)\n .sort((a, b) => a.createdAt.localeCompare(b.createdAt))\n }\n\n // ── Visitors ──────────────────────────────────────────────────────────────\n\n async createVisitor(data: CreateVisitorInput): Promise<Visitor> {\n const now = new Date().toISOString()\n const visitor: Visitor = {\n id: randomUUID(),\n tenantId: data.tenantId,\n visitorId: data.visitorId,\n firstSeen: now,\n lastSeen: now,\n ...(data.country != null && { country: data.country }),\n ...(data.region != null && { region: data.region }),\n ...(data.city != null && { city: data.city }),\n ...(data.ipHash != null && { ipHash: data.ipHash }),\n ...(data.userAgentHash != null && { userAgentHash: data.userAgentHash }),\n }\n this.db.visitors.push(visitor)\n this.scheduleWrite()\n return visitor\n }\n\n async updateVisitor(visitorId: string, data: UpdateVisitorInput): Promise<Visitor> {\n const idx = this.db.visitors.findIndex(v => v.visitorId === visitorId)\n if (idx === -1) throw new Error(`Visitor ${visitorId} not found`)\n const existing = this.db.visitors[idx]!\n const updated: Visitor = {\n ...existing,\n lastSeen: data.lastSeen ?? new Date().toISOString(),\n ...(data.country != null && { country: data.country }),\n ...(data.region != null && { region: data.region }),\n ...(data.city != null && { city: data.city }),\n }\n this.db.visitors[idx] = updated\n this.scheduleWrite()\n return updated\n }\n\n async deleteVisitor(visitorId: string): Promise<void> {\n this.db.visitors = this.db.visitors.filter(v => v.visitorId !== visitorId)\n this.scheduleWrite()\n }\n\n async getVisitor(visitorId: string): Promise<Visitor | null> {\n return this.db.visitors.find(v => v.visitorId === visitorId) ?? null\n }\n\n async getVisitors(filters: VisitorFilters): Promise<Visitor[]> {\n let rows = this.db.visitors.filter(v => v.tenantId === filters.tenantId)\n if (filters.from) rows = rows.filter(v => v.firstSeen >= filters.from!)\n if (filters.to) rows = rows.filter(v => v.firstSeen <= filters.to!)\n rows.sort((a, b) => b.lastSeen.localeCompare(a.lastSeen))\n return page(rows, filters.page ?? 1, filters.limit ?? 50)\n }\n\n // ── Users ──────────────────────────────────────────────────────────────────\n\n async createUser(data: CreateUserInput): Promise<AdminUser> {\n const now = new Date().toISOString()\n const user: AdminUser = {\n id: randomUUID(),\n tenantId: data.tenantId,\n name: data.name,\n email: data.email,\n passwordHash: data.passwordHash,\n isActive: true,\n createdAt: now,\n updatedAt: now,\n }\n this.db.users.push(user)\n this.scheduleWrite()\n return user\n }\n\n async updateUser(id: string, data: UpdateUserInput): Promise<AdminUser> {\n const idx = this.db.users.findIndex(u => u.id === id)\n if (idx === -1) throw new Error(`User ${id} not found`)\n const existing = this.db.users[idx]!\n const updated: AdminUser = {\n ...existing,\n ...(data.name != null && { name: data.name }),\n ...(data.email != null && { email: data.email }),\n ...(data.passwordHash != null && { passwordHash: data.passwordHash }),\n ...(data.isActive != null && { isActive: data.isActive }),\n ...('totpSecret' in data && data.totpSecret != null && { totpSecret: data.totpSecret }),\n ...(data.totpEnabled != null && { totpEnabled: data.totpEnabled }),\n updatedAt: new Date().toISOString(),\n }\n this.db.users[idx] = updated\n this.scheduleWrite()\n return updated\n }\n\n async deleteUser(id: string): Promise<void> {\n this.db.user_roles = this.db.user_roles.filter(ur => ur.userId !== id)\n this.db.users = this.db.users.filter(u => u.id !== id)\n this.scheduleWrite()\n }\n\n async getUserById(id: string): Promise<AdminUser | null> {\n return this.db.users.find(u => u.id === id) ?? null\n }\n\n async getUserByEmail(email: string): Promise<AdminUser | null> {\n return this.db.users.find(u => u.email === email) ?? null\n }\n\n async getUsers(tenantId: string): Promise<AdminUser[]> {\n return this.db.users.filter(u => u.tenantId === tenantId)\n .sort((a, b) => a.createdAt.localeCompare(b.createdAt))\n }\n\n async countUsers(tenantId?: string): Promise<number> {\n return tenantId\n ? this.db.users.filter(u => u.tenantId === tenantId).length\n : this.db.users.length\n }\n\n // ── Roles & Permissions ────────────────────────────────────────────────────\n\n async getRoles(tenantId: string): Promise<Role[]> {\n return this.db.roles.filter(r => r.tenantId === tenantId)\n }\n\n async createRole(data: CreateRoleInput): Promise<Role> {\n const role: Role = {\n id: randomUUID(),\n tenantId: data.tenantId,\n name: data.name,\n ...(data.description != null && { description: data.description }),\n }\n this.db.roles.push(role)\n this.scheduleWrite()\n return role\n }\n\n async updateRole(id: string, data: UpdateRoleInput): Promise<Role> {\n const idx = this.db.roles.findIndex(r => r.id === id)\n if (idx === -1) throw new Error(`Role ${id} not found`)\n const updated: Role = {\n ...this.db.roles[idx]!,\n ...(data.name != null && { name: data.name }),\n ...(data.description != null && { description: data.description }),\n }\n this.db.roles[idx] = updated\n this.scheduleWrite()\n return updated\n }\n\n async deleteRole(id: string): Promise<void> {\n this.db.role_permissions = this.db.role_permissions.filter(rp => rp.roleId !== id)\n this.db.user_roles = this.db.user_roles.filter(ur => ur.roleId !== id)\n this.db.roles = this.db.roles.filter(r => r.id !== id)\n this.scheduleWrite()\n }\n\n async getAllPermissions(): Promise<Permission[]> {\n return [...this.db.permissions].sort((a, b) => a.name.localeCompare(b.name))\n }\n\n async getPermissionsForRole(roleId: string): Promise<Permission[]> {\n const permIds = new Set(\n this.db.role_permissions.filter(rp => rp.roleId === roleId).map(rp => rp.permissionId)\n )\n return this.db.permissions.filter(p => permIds.has(p.id))\n }\n\n async getUserRoles(userId: string, tenantId?: string): Promise<Role[]> {\n let urs = this.db.user_roles.filter(ur => ur.userId === userId)\n if (tenantId) urs = urs.filter(ur => ur.tenantId === tenantId)\n const roleIds = new Set(urs.map(ur => ur.roleId))\n return this.db.roles.filter(r => roleIds.has(r.id))\n }\n\n async assignRole(userId: string, roleId: string, tenantId = 'default'): Promise<void> {\n if (!this.db.user_roles.find(ur => ur.userId === userId && ur.roleId === roleId && ur.tenantId === tenantId)) {\n this.db.user_roles.push({ userId, roleId, tenantId })\n this.scheduleWrite()\n }\n }\n\n async revokeRole(userId: string, roleId: string, tenantId?: string): Promise<void> {\n this.db.user_roles = this.db.user_roles.filter(ur =>\n !(ur.userId === userId && ur.roleId === roleId && (tenantId == null || ur.tenantId === tenantId))\n )\n this.scheduleWrite()\n }\n\n async assignPermissionToRole(roleId: string, permissionId: string): Promise<void> {\n if (!this.db.role_permissions.find(rp => rp.roleId === roleId && rp.permissionId === permissionId)) {\n this.db.role_permissions.push({ roleId, permissionId })\n this.scheduleWrite()\n }\n }\n\n async revokePermissionFromRole(roleId: string, permissionId: string): Promise<void> {\n this.db.role_permissions = this.db.role_permissions.filter(\n rp => !(rp.roleId === roleId && rp.permissionId === permissionId)\n )\n this.scheduleWrite()\n }\n\n // ── Audit ──────────────────────────────────────────────────────────────────\n\n async createLog(data: CreateAuditLogInput): Promise<void> {\n const log: AuditLog = {\n id: randomUUID(),\n tenantId: data.tenantId,\n action: data.action,\n resourceType: data.resourceType,\n createdAt: new Date().toISOString(),\n ...(data.userId != null && { userId: data.userId }),\n ...(data.resourceId != null && { resourceId: data.resourceId }),\n ...(data.oldData != null && { oldData: data.oldData }),\n ...(data.newData != null && { newData: data.newData }),\n }\n this.db.audit_logs.push(log)\n this.scheduleWrite()\n }\n\n async getLogs(filters: AuditFilters): Promise<AuditLog[]> {\n let rows = this.db.audit_logs.filter(l => l.tenantId === filters.tenantId)\n if (filters.action) rows = rows.filter(l => l.action === filters.action)\n if (filters.resourceType) rows = rows.filter(l => l.resourceType === filters.resourceType)\n if (filters.from) rows = rows.filter(l => l.createdAt >= filters.from!)\n if (filters.to) rows = rows.filter(l => l.createdAt <= filters.to!)\n rows.sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n return page(rows, filters.page ?? 1, filters.limit ?? 50)\n }\n\n async *streamAuditLogs(filters: AuditFilters): AsyncIterable<AuditLog> {\n let rows = this.db.audit_logs.filter(l => l.tenantId === filters.tenantId)\n if (filters.action) rows = rows.filter(l => l.action === filters.action)\n if (filters.from) rows = rows.filter(l => l.createdAt >= filters.from!)\n if (filters.to) rows = rows.filter(l => l.createdAt <= filters.to!)\n rows.sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n for (const log of rows) yield log\n }\n\n // ── Stats ──────────────────────────────────────────────────────────────────\n\n async getOverviewStats(tenantId: string): Promise<OverviewStats> {\n const consents = this.db.consents.filter(c => c.tenantId === tenantId)\n const recent = consents.slice(-500)\n let accepted = 0, rejected = 0\n for (const c of recent) {\n const vals = Object.values(c.consentJson)\n const grantedPct = vals.length > 0 ? vals.filter(v => v === 'granted').length / vals.length : 0\n if (grantedPct >= 0.8) accepted++\n else if (grantedPct <= 0.2) rejected++\n }\n const sample = recent.length || 1\n return {\n totalConsents: consents.length,\n gpcDetectedCount: consents.filter(c => c.gpcDetected).length,\n totalVisitors: this.db.visitors.filter(v => v.tenantId === tenantId).length,\n acceptedPct: Math.round((accepted / sample) * 100),\n rejectedPct: Math.round((rejected / sample) * 100),\n }\n }\n\n async getCategoryStats(tenantId: string): Promise<CategoryStats> {\n const stats: CategoryStats = {}\n for (const c of this.db.consents.filter(c => c.tenantId === tenantId).slice(0, 5000)) {\n for (const [key, status] of Object.entries(c.consentJson)) {\n if (!stats[key]) stats[key] = { granted: 0, denied: 0, objected: 0 }\n if (status === 'granted') stats[key]!.granted++\n else if (status === 'denied') stats[key]!.denied++\n else if (status === 'objected') stats[key]!.objected++\n }\n }\n return stats\n }\n\n async getTimeline(tenantId: string, days = 30): Promise<TimelineEntry[]> {\n const cutoff = new Date(Date.now() - days * 86_400_000).toISOString().slice(0, 10)\n const counts = new Map<string, number>()\n for (const c of this.db.consents.filter(c => c.tenantId === tenantId && c.createdAt.slice(0, 10) >= cutoff)) {\n const date = c.createdAt.slice(0, 10)\n counts.set(date, (counts.get(date) ?? 0) + 1)\n }\n return [...counts.entries()]\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([date, count]) => ({ date, count }))\n }\n\n async getCountries(tenantId: string): Promise<CountryStat[]> {\n const consentVisitors = new Set(\n this.db.consents.filter(c => c.tenantId === tenantId).map(c => c.visitorId)\n )\n const counts = new Map<string, number>()\n for (const v of this.db.visitors.filter(v => consentVisitors.has(v.visitorId) && v.country)) {\n const c = v.country!\n counts.set(c, (counts.get(c) ?? 0) + 1)\n }\n return [...counts.entries()]\n .sort(([, a], [, b]) => b - a)\n .slice(0, 50)\n .map(([country, count]) => ({ country, count }))\n }\n\n async getGpcStats(tenantId: string): Promise<GpcStats> {\n const consents = this.db.consents.filter(c => c.tenantId === tenantId)\n const detected = consents.filter(c => c.gpcDetected).length\n const total = consents.length\n return { detected, total, rate: total > 0 ? Math.round((detected / total) * 100) : 0 }\n }\n\n // ── Tenants ────────────────────────────────────────────────────────────────\n\n async getTenants(): Promise<Tenant[]> {\n return [...this.db.tenants].sort((a, b) => a.name.localeCompare(b.name))\n }\n\n async createTenant(data: CreateTenantInput): Promise<Tenant> {\n const now = new Date().toISOString()\n const tenant: Tenant = { id: randomUUID(), name: data.name, slug: data.slug, createdAt: now, updatedAt: now }\n this.db.tenants.push(tenant)\n this.scheduleWrite()\n return tenant\n }\n\n async updateTenant(id: string, data: UpdateTenantInput): Promise<Tenant> {\n const idx = this.db.tenants.findIndex(t => t.id === id)\n if (idx === -1) throw new Error(`Tenant ${id} not found`)\n const now = new Date().toISOString()\n const updated: Tenant = {\n ...this.db.tenants[idx]!,\n ...(data.name != null && { name: data.name }),\n ...(data.slug != null && { slug: data.slug }),\n updatedAt: now,\n }\n this.db.tenants[idx] = updated\n this.scheduleWrite()\n return updated\n }\n\n async deleteTenant(id: string): Promise<void> {\n this.db.tenants = this.db.tenants.filter(t => t.id !== id)\n this.scheduleWrite()\n }\n\n async purgeExpiredConsents(olderThanDays: number): Promise<number> {\n const cutoff = new Date(Date.now() - olderThanDays * 86_400_000).toISOString()\n const toDelete = new Set(\n this.db.consents.filter(c => c.createdAt < cutoff).map(c => c.visitorId)\n )\n if (toDelete.size === 0) return 0\n this.db.consent_history = this.db.consent_history.filter(h => !toDelete.has(h.visitorId))\n this.db.consents = this.db.consents.filter(c => !toDelete.has(c.visitorId))\n this.scheduleWrite()\n return toDelete.size\n }\n\n // ── API Keys ───────────────────────────────────────────────────────────────\n\n async createApiKey(data: CreateApiKeyInput): Promise<ApiKey> {\n const key: ApiKey = {\n id: randomUUID(),\n tenantId: data.tenantId,\n keyHash: data.keyHash,\n name: data.name,\n isActive: true,\n createdAt: new Date().toISOString(),\n }\n this.db.api_keys.push(key)\n this.scheduleWrite()\n return key\n }\n\n async getApiKeyByHash(keyHash: string): Promise<ApiKey | null> {\n return this.db.api_keys.find(k => k.keyHash === keyHash && k.isActive) ?? null\n }\n\n async revokeApiKey(id: string): Promise<void> {\n const key = this.db.api_keys.find(k => k.id === id)\n if (key) { key.isActive = false; this.scheduleWrite() }\n }\n\n async getApiKeys(tenantId: string): Promise<ApiKey[]> {\n return this.db.api_keys\n .filter(k => k.tenantId === tenantId)\n .sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n }\n\n // ── Cookie Templates ───────────────────────────────────────────────────────\n\n async createCookieTemplate(data: CreateCookieTemplateInput): Promise<ServerCookieTemplate> {\n const now = new Date().toISOString()\n const tpl: ServerCookieTemplate = {\n id: randomUUID(), tenantId: data.tenantId, name: data.name,\n cookies: data.cookies, createdAt: now, updatedAt: now,\n }\n this.db.cookie_templates.push(tpl)\n this.scheduleWrite()\n return tpl\n }\n\n async updateCookieTemplate(id: string, data: UpdateCookieTemplateInput): Promise<ServerCookieTemplate> {\n const idx = this.db.cookie_templates.findIndex(t => t.id === id)\n if (idx === -1) throw new Error('Cookie template not found')\n const now = new Date().toISOString()\n const updated: ServerCookieTemplate = {\n ...this.db.cookie_templates[idx]!,\n ...(data.name !== undefined && { name: data.name }),\n ...(data.cookies !== undefined && { cookies: data.cookies }),\n updatedAt: now,\n }\n this.db.cookie_templates[idx] = updated\n this.scheduleWrite()\n return updated\n }\n\n async deleteCookieTemplate(id: string): Promise<void> {\n this.db.cookie_templates = this.db.cookie_templates.filter(t => t.id !== id)\n this.scheduleWrite()\n }\n\n async getCookieTemplate(id: string): Promise<ServerCookieTemplate | null> {\n return this.db.cookie_templates.find(t => t.id === id) ?? null\n }\n\n async getCookieTemplates(tenantId: string): Promise<ServerCookieTemplate[]> {\n return this.db.cookie_templates\n .filter(t => t.tenantId === tenantId)\n .sort((a, b) => a.name.localeCompare(b.name))\n }\n\n async copyCookieTemplate(id: string, newName: string): Promise<ServerCookieTemplate> {\n const src = await this.getCookieTemplate(id)\n if (!src) throw new Error('Cookie template not found')\n return this.createCookieTemplate({ tenantId: src.tenantId, name: newName, cookies: src.cookies })\n }\n\n // ── UI Templates ───────────────────────────────────────────────────────────\n\n async createUITemplate(data: CreateUITemplateInput): Promise<ServerUITemplate> {\n const now = new Date().toISOString()\n const { tenantId, name, ...settings } = data\n const tpl = { id: randomUUID(), tenantId, name, ...settings, createdAt: now, updatedAt: now } as ServerUITemplate\n this.db.ui_templates.push(tpl)\n this.scheduleWrite()\n return tpl\n }\n\n async updateUITemplate(id: string, data: UpdateUITemplateInput): Promise<ServerUITemplate> {\n const idx = this.db.ui_templates.findIndex(t => t.id === id)\n if (idx === -1) throw new Error('UI template not found')\n const { name: _name, ...settings } = data\n const now = new Date().toISOString()\n const updated = {\n ...this.db.ui_templates[idx]!,\n ...(data.name !== undefined && { name: data.name }),\n ...settings,\n updatedAt: now,\n } as ServerUITemplate\n this.db.ui_templates[idx] = updated\n this.scheduleWrite()\n return updated\n }\n\n async deleteUITemplate(id: string): Promise<void> {\n this.db.ui_templates = this.db.ui_templates.filter(t => t.id !== id)\n this.scheduleWrite()\n }\n\n async getUITemplate(id: string): Promise<ServerUITemplate | null> {\n return this.db.ui_templates.find(t => t.id === id) ?? null\n }\n\n async getUITemplates(tenantId: string): Promise<ServerUITemplate[]> {\n return this.db.ui_templates\n .filter(t => t.tenantId === tenantId)\n .sort((a, b) => a.name.localeCompare(b.name))\n }\n\n async copyUITemplate(id: string, newName: string): Promise<ServerUITemplate> {\n const src = await this.getUITemplate(id)\n if (!src) throw new Error('UI template not found')\n const { tenantId, mainBanner, gpcBanner, preferenceModal } = src as ServerUITemplate & {\n mainBanner?: unknown; gpcBanner?: unknown; preferenceModal?: unknown\n }\n return this.createUITemplate({\n tenantId, name: newName,\n ...(mainBanner !== undefined && { mainBanner }),\n ...(gpcBanner !== undefined && { gpcBanner }),\n ...(preferenceModal !== undefined && { preferenceModal }),\n } as CreateUITemplateInput)\n }\n}\n","import type {\n StorageAdapter, Profile, CreateProfileInput, UpdateProfileInput,\n} from '@consenti/types'\n\nexport class ProfileRepo {\n constructor(private adapter: StorageAdapter) {}\n\n create(data: CreateProfileInput): Promise<Profile> {\n return this.adapter.createProfile(data)\n }\n\n update(id: string, data: UpdateProfileInput): Promise<Profile> {\n return this.adapter.updateProfile(id, data)\n }\n\n delete(id: string): Promise<void> {\n return this.adapter.deleteProfile(id)\n }\n\n get(id: string): Promise<Profile | null> {\n return this.adapter.getProfile(id)\n }\n\n list(tenantId: string): Promise<Profile[]> {\n return this.adapter.getProfiles(tenantId)\n }\n}\n","import type {\n StorageAdapter, ConsentDbRecord, CreateConsentInput, UpdateConsentInput, ConsentFilters,\n} from '@consenti/types'\n\nexport class ConsentRepo {\n constructor(private adapter: StorageAdapter) {}\n\n create(data: CreateConsentInput): Promise<ConsentDbRecord> {\n return this.adapter.createConsent(data)\n }\n\n update(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord> {\n return this.adapter.updateConsent(visitorId, data)\n }\n\n delete(visitorId: string): Promise<void> {\n return this.adapter.deleteConsent(visitorId)\n }\n\n get(visitorId: string): Promise<ConsentDbRecord | null> {\n return this.adapter.getConsent(visitorId)\n }\n\n list(filters: ConsentFilters): Promise<ConsentDbRecord[]> {\n return this.adapter.getConsents(filters)\n }\n}\n","import type {\n StorageAdapter, Visitor, CreateVisitorInput, UpdateVisitorInput,\n} from '@consenti/types'\n\nexport class VisitorRepo {\n constructor(private adapter: StorageAdapter) {}\n\n create(data: CreateVisitorInput): Promise<Visitor> {\n return this.adapter.createVisitor(data)\n }\n\n update(visitorId: string, data: UpdateVisitorInput): Promise<Visitor> {\n return this.adapter.updateVisitor(visitorId, data)\n }\n\n delete(visitorId: string): Promise<void> {\n return this.adapter.deleteVisitor(visitorId)\n }\n\n get(visitorId: string): Promise<Visitor | null> {\n return this.adapter.getVisitor(visitorId)\n }\n}\n","import type {\n StorageAdapter, AuditLog, AuditFilters, CreateAuditLogInput,\n} from '@consenti/types'\n\nexport class AuditRepo {\n constructor(private adapter: StorageAdapter) {}\n\n log(data: CreateAuditLogInput): Promise<void> {\n return this.adapter.createLog(data)\n }\n\n list(filters: AuditFilters): Promise<AuditLog[]> {\n return this.adapter.getLogs(filters)\n }\n}\n","import type {\n StorageAdapter,\n AdminUser,\n CreateUserInput,\n UpdateUserInput,\n Role,\n} from '@consenti/types'\n\nexport class UserRepo {\n constructor(private adapter: StorageAdapter) {}\n\n getById(id: string): Promise<AdminUser | null> { return this.adapter.getUserById(id) }\n getByEmail(email: string): Promise<AdminUser | null> { return this.adapter.getUserByEmail(email) }\n list(tenantId: string): Promise<AdminUser[]> { return this.adapter.getUsers(tenantId) }\n create(data: CreateUserInput): Promise<AdminUser> { return this.adapter.createUser(data) }\n update(id: string, data: UpdateUserInput): Promise<AdminUser> { return this.adapter.updateUser(id, data) }\n delete(id: string): Promise<void> { return this.adapter.deleteUser(id) }\n getRoles(userId: string, tenantId?: string): Promise<Role[]> { return this.adapter.getUserRoles(userId, tenantId) }\n assignRole(userId: string, roleId: string, tenantId?: string): Promise<void> { return this.adapter.assignRole(userId, roleId, tenantId) }\n revokeRole(userId: string, roleId: string, tenantId?: string): Promise<void> { return this.adapter.revokeRole(userId, roleId, tenantId) }\n}\n","import type { Profile, LocaleTranslations, ProfileTranslations } from '@consenti/types'\n\nfunction mergeTranslations(base: LocaleTranslations, override: Partial<LocaleTranslations>): LocaleTranslations {\n return {\n mainBanner: { ...base.mainBanner, ...override.mainBanner },\n preferenceModal: {\n ...base.preferenceModal,\n ...override.preferenceModal,\n buttons: override.preferenceModal?.buttons ?? base.preferenceModal.buttons,\n categories: override.preferenceModal?.categories ?? base.preferenceModal.categories,\n },\n ...(override.gpcBanner != null || base.gpcBanner != null\n ? { gpcBanner: { ...(base.gpcBanner ?? base.mainBanner), ...override.gpcBanner } }\n : {}),\n }\n}\n\nexport function resolveLocale(\n translations: ProfileTranslations,\n requested: string,\n defaultLocale: string,\n): LocaleTranslations {\n const base = translations[defaultLocale]\n if (!base) throw new Error(`Default locale '${defaultLocale}' not found in translations`)\n\n if (requested === defaultLocale) return base\n\n const exact = translations[requested]\n if (exact) return mergeTranslations(base, exact)\n\n const lang = requested.split('-')[0] ?? ''\n const langMatch = lang ? translations[lang] : undefined\n if (langMatch) return mergeTranslations(base, langMatch)\n\n return base\n}\n\nexport function resolveProfile(\n profile: Profile,\n locale: string,\n): { profile: Profile; resolved: LocaleTranslations } {\n const translations = profile.profileJson.translations ?? {}\n const resolved = resolveLocale(translations, locale, profile.defaultLocale)\n return { profile, resolved }\n}\n\nexport function bumpVersion(profile: Profile): number {\n return profile.version + 1\n}\n","import type { Profile, CreateProfileInput, UpdateProfileInput, PublicProfileResponse, StorageAdapter, LocaleTextContent, ServerUITemplate, LocaleTranslations, ButtonStyle, ButtonAction } from '@consenti/types'\nimport { resolveLocale } from '../core/profile-engine'\nimport type { ProfileRepo } from '../repositories/profile.repo'\nimport type { AuditRepo } from '../repositories/audit.repo'\n\nfunction buildTranslations(template: ServerUITemplate, localeContents: Record<string, LocaleTextContent>): Record<string, LocaleTranslations> {\n const result: Record<string, LocaleTranslations> = {}\n for (const [locale, content] of Object.entries(localeContents)) {\n result[locale] = {\n mainBanner: {\n position: template.mainBanner.position as LocaleTranslations['mainBanner']['position'],\n overlayOpacity: template.mainBanner.overlayOpacity,\n showClose: template.mainBanner.showClose,\n headingTag: template.mainBanner.headingTag,\n heading: content.mainBanner.heading,\n htmlText: content.mainBanner.htmlText,\n buttons: template.mainBanner.buttons.map((btn, i) => ({\n text: content.mainBanner.buttonLabels[i] ?? btn.text,\n style: btn.type as ButtonStyle,\n action: btn.action as ButtonAction,\n ...(btn.cookies != null ? { cookies: btn.cookies as '*' | '!' | string[] } : {}),\n })),\n },\n gpcBanner: {\n position: template.gpcBanner.position as LocaleTranslations['mainBanner']['position'],\n overlayOpacity: template.gpcBanner.overlayOpacity,\n showClose: template.gpcBanner.showClose,\n headingTag: template.gpcBanner.headingTag,\n heading: content.gpcBanner.heading,\n htmlText: content.gpcBanner.htmlText,\n buttons: template.gpcBanner.buttons.map((btn, i) => ({\n text: content.gpcBanner.buttonLabels[i] ?? btn.text,\n style: btn.type as ButtonStyle,\n action: btn.action as ButtonAction,\n ...(btn.cookies != null ? { cookies: btn.cookies as '*' | '!' | string[] } : {}),\n })),\n },\n preferenceModal: {\n position: template.preferenceModal.position as 'left' | 'right' | 'center',\n overlayOpacity: template.preferenceModal.overlayOpacity,\n showClose: template.preferenceModal.showClose,\n persistent: template.preferenceModal.persistent,\n headingTag: template.preferenceModal.headingTag,\n heading: content.preferenceModal.heading ?? '',\n ...(content.preferenceModal.subheading ? { subheading: content.preferenceModal.subheading } : {}),\n ...(content.preferenceModal.htmlText ? { htmlText: content.preferenceModal.htmlText } : {}),\n buttons: template.preferenceModal.buttons.map((btn, i) => ({\n text: content.preferenceModal.buttonLabels[i] ?? btn.text,\n style: btn.type as ButtonStyle,\n action: btn.action as ButtonAction,\n ...(btn.cookies != null ? { cookies: btn.cookies as '*' | '!' | string[] } : {}),\n })),\n categories: template.preferenceModal.categories.map(cat => {\n const c = content.preferenceModal.categories.find(c => c.id === cat.id)\n return {\n id: cat.id,\n heading: c?.heading ?? cat.id,\n headingTag: cat.headingTag,\n htmlText: c?.htmlText ?? '',\n mandatory: cat.mandatory,\n type: cat.type,\n ...(cat.liEnabled ? { legitimateInterest: { enabled: true } } : {}),\n cookies: cat.cookies,\n }\n }),\n },\n }\n }\n return result\n}\n\nexport class ProfileService {\n constructor(\n private profiles: ProfileRepo,\n private audit: AuditRepo,\n private tenantId: string = 'default',\n private storage?: StorageAdapter,\n ) {}\n\n async create(input: Omit<CreateProfileInput, 'tenantId'>): Promise<Profile> {\n const profile = await this.profiles.create({ ...input, tenantId: this.tenantId })\n await this.audit.log({\n tenantId: this.tenantId,\n action: 'profile.created',\n resourceType: 'profile',\n resourceId: profile.id,\n newData: profile,\n })\n return profile\n }\n\n async update(id: string, input: UpdateProfileInput): Promise<Profile> {\n const old = await this.profiles.get(id)\n const profile = await this.profiles.update(id, input)\n await this.audit.log({\n tenantId: this.tenantId,\n action: 'profile.updated',\n resourceType: 'profile',\n resourceId: id,\n ...(old != null ? { oldData: old } : {}),\n newData: profile,\n })\n return profile\n }\n\n async delete(id: string): Promise<void> {\n const old = await this.profiles.get(id)\n await this.profiles.delete(id)\n await this.audit.log({\n tenantId: this.tenantId,\n action: 'profile.deleted',\n resourceType: 'profile',\n resourceId: id,\n ...(old != null ? { oldData: old } : {}),\n })\n }\n\n async get(id: string, locale?: string): Promise<Profile | null> {\n const profile = await this.profiles.get(id)\n if (!profile) return null\n if (!locale) return profile\n const resolved = resolveLocale(profile.profileJson.translations ?? {}, locale, profile.defaultLocale)\n return {\n ...profile,\n profileJson: {\n ...profile.profileJson,\n translations: { [locale]: resolved },\n },\n }\n }\n\n async getResolved(id: string, locale?: string): Promise<PublicProfileResponse | null> {\n const profile = await this.profiles.get(id)\n if (!profile) return null\n const pj = profile.profileJson\n\n let cookies = pj.cookies ?? []\n let translations = pj.translations ?? {}\n\n if (pj.cookieTemplateId && this.storage) {\n const ct = await this.storage.getCookieTemplate(pj.cookieTemplateId)\n if (ct) cookies = ct.cookies\n }\n\n if (pj.uiTemplateId && pj.localeContents && this.storage) {\n const ut = await this.storage.getUITemplate(pj.uiTemplateId)\n if (ut) translations = buildTranslations(ut, pj.localeContents)\n }\n\n const currentLocale = locale ?? profile.defaultLocale\n const localeKeys = pj.localeContents ? Object.keys(pj.localeContents) : Object.keys(translations)\n const resolved = resolveLocale(translations, currentLocale, profile.defaultLocale)\n return {\n id: profile.id,\n version: profile.version,\n defaultLocale: profile.defaultLocale,\n currentLocale,\n locales: localeKeys,\n cookies,\n mainBanner: resolved.mainBanner,\n preferenceModal: resolved.preferenceModal,\n ...(resolved.gpcBanner != null ? { gpcBanner: resolved.gpcBanner } : {}),\n }\n }\n\n list(): Promise<Profile[]> {\n return this.profiles.list(this.tenantId)\n }\n}\n","import type {\n ConsentDbRecord,\n ConsentValue,\n ConsentVerifyResult,\n CreateConsentInput,\n Profile,\n Cookie,\n} from '@consenti/types'\n\nexport interface ConsentValidationResult {\n valid: boolean\n errors: string[]\n}\n\nexport function validateConsentInput(\n data: Pick<CreateConsentInput, 'consentJson'>,\n profile: Profile,\n): ConsentValidationResult {\n const errors: string[] = []\n for (const [cookieId, status] of Object.entries(data.consentJson)) {\n const cookie = (profile.profileJson.cookies ?? []).find(c => c.id === cookieId)\n if (!cookie) continue\n if (cookie.mandatory && status !== 'granted') {\n errors.push(`Cookie \"${cookieId}\" is mandatory and cannot be \"${status}\"`)\n }\n if (status === 'objected' && cookie.type !== 'legitimate_interest') {\n errors.push(`Cookie \"${cookieId}\" is type \"${cookie.type ?? 'consent'}\" — 'objected' is only valid for 'legitimate_interest'`)\n }\n }\n return { valid: errors.length === 0, errors }\n}\n\nexport function buildConsentValue(\n cookies: Profile['profileJson']['cookies'],\n submitted: ConsentValue,\n gpcDetected: boolean,\n regulation?: string,\n): ConsentValue {\n const result: ConsentValue = {}\n for (const cookie of (cookies ?? [])) {\n const id = cookie.id\n if (cookie.mandatory) {\n result[id] = 'granted'\n continue\n }\n // CPRA: GPC triggers Do Not Sell + Do Not Share; sensitive data requires explicit opt-in\n if (regulation === 'cpra') {\n if (cookie.cpraCategory === 'sensitive') {\n // Sensitive data is opt-in even under CPRA — treat like GDPR (deny by default)\n const status = submitted[id]\n result[id] = (status === 'granted' || status === 'denied' || status === 'objected') ? status : 'denied'\n continue\n }\n if (gpcDetected && (cookie.cpraCategory === 'sale' || cookie.cpraCategory === 'sharing')) {\n result[id] = 'denied'\n continue\n }\n }\n // GDPR/CCPA/DPDPA: honor listenGpc flag\n if (gpcDetected && cookie.listenGpc && regulation !== 'dpdpa') {\n result[id] = 'denied'\n continue\n }\n const status = submitted[id]\n if (status === 'granted' || status === 'denied' || status === 'objected') {\n result[id] = status\n } else {\n result[id] = 'denied'\n }\n }\n return result\n}\n\nexport function verifyConsent(\n record: ConsentDbRecord,\n profile: Profile,\n): ConsentVerifyResult {\n const reasons: ConsentVerifyResult['reasons'] = []\n\n if (record.profileVersion < profile.version) {\n reasons.push('profile_version_mismatch')\n }\n\n if (isExpired(record, profile)) {\n reasons.push('consent_expired')\n }\n\n return {\n valid: reasons.length === 0,\n reasons,\n currentProfileVersion: profile.version,\n consentProfileVersion: record.profileVersion,\n }\n}\n\nexport function buildTcfPayload(\n cookies: Cookie[],\n consentValue: ConsentValue,\n): { vendorConsents: number[]; purposeConsents: number[] } {\n const vendorSet = new Set<number>()\n const purposeSet = new Set<number>()\n for (const cookie of cookies) {\n if (consentValue[cookie.id] !== 'granted') continue\n if (cookie.tcfVendorId) vendorSet.add(cookie.tcfVendorId)\n for (const p of cookie.tcfPurposes ?? []) purposeSet.add(p)\n }\n return {\n vendorConsents: [...vendorSet].sort((a, b) => a - b),\n purposeConsents: [...purposeSet].sort((a, b) => a - b),\n }\n}\n\nfunction isExpired(record: ConsentDbRecord, profile: Profile): boolean {\n const cookies = profile.profileJson.cookies ?? []\n const createdMs = new Date(record.createdAt).getTime()\n const now = Date.now()\n\n for (const cookie of cookies) {\n if (!cookie.expiry) continue\n const expiryMs = createdMs + cookie.expiry * 24 * 60 * 60 * 1000\n if (now > expiryMs) return true\n }\n return false\n}\n","// Simplified TC string encoder/decoder.\n// This implementation stores a base64url-encoded JSON payload for basic compatibility.\n// For full IAB TCF v2.2 compliance (binary bitfield encoding), use the iabtcf-core npm package.\n\nexport interface TcStringInput {\n cmpId: number\n cmpVersion: number\n consentScreen: number\n consentLanguage: string\n vendorListVersion: number\n purposeConsents: number[]\n vendorConsents: number[]\n}\n\nexport function encodeTcString(input: TcStringInput): string {\n const payload = {\n v: 2,\n ts: Math.floor(Date.now() / 100),\n cmpId: input.cmpId,\n cmpV: input.cmpVersion,\n cs: input.consentScreen,\n lang: input.consentLanguage.toUpperCase().slice(0, 2),\n vlV: input.vendorListVersion,\n pc: input.purposeConsents,\n vc: input.vendorConsents,\n }\n return Buffer.from(JSON.stringify(payload)).toString('base64url')\n}\n\nexport interface DecodedTcString {\n version: number\n cmpId: number\n consentLanguage: string\n purposeConsents: number[]\n vendorConsents: number[]\n created: number\n}\n\nexport function decodeTcString(tcString: string): DecodedTcString | null {\n try {\n const raw = JSON.parse(Buffer.from(tcString, 'base64url').toString('utf8')) as {\n v: number; cmpId: number; lang: string; pc: number[]; vc: number[]; ts: number\n }\n return {\n version: raw.v,\n cmpId: raw.cmpId,\n consentLanguage: raw.lang,\n purposeConsents: Array.isArray(raw.pc) ? raw.pc : [],\n vendorConsents: Array.isArray(raw.vc) ? raw.vc : [],\n created: raw.ts * 100,\n }\n } catch {\n return null\n }\n}\n","import type {\n ConsentDbRecord, ConsentVerifyResult, CreateConsentInput, UpdateConsentInput,\n ComplianceConfig, TcfConfig,\n} from '@consenti/types'\nimport { buildConsentValue, verifyConsent, validateConsentInput, buildTcfPayload } from '../core/consent-engine'\nimport { encodeTcString } from '../tcf/tc-string'\nimport { getGvl } from '../tcf/gvl-cache'\nimport type { ConsentRepo } from '../repositories/consent.repo'\nimport type { VisitorRepo } from '../repositories/visitor.repo'\nimport type { ProfileRepo } from '../repositories/profile.repo'\nimport type { AuditRepo } from '../repositories/audit.repo'\nimport type { PluginEngine } from '../core/plugin-engine'\nimport type { EventEmitter } from 'node:events'\n\nexport class ConsentService {\n constructor(\n private consents: ConsentRepo,\n private visitors: VisitorRepo,\n private profiles: ProfileRepo,\n private audit: AuditRepo,\n private tenantId: string = 'default',\n private compliance?: ComplianceConfig,\n private pluginEngine?: PluginEngine,\n private eventBus?: EventEmitter,\n private tcfConfig?: TcfConfig,\n ) {}\n\n async create(input: Omit<CreateConsentInput, 'tenantId'>): Promise<ConsentDbRecord> {\n const profile = await this.profiles.get(input.profileId)\n if (!profile) throw new Error(`Profile ${input.profileId} not found`)\n\n const regulation = profile.profileJson.regulation\n const profileCookies = profile.profileJson.cookies ?? []\n // GPC server-side enforcement — skip for DPDPA (no GPC opt-out signal recognised)\n let effectiveConsent = input.consentJson\n if (input.gpcDetected && this.compliance?.gpc !== false && regulation !== 'dpdpa') {\n effectiveConsent = { ...effectiveConsent }\n for (const cookie of profileCookies) {\n if (regulation === 'cpra') {\n // CPRA: deny sale + sharing on GPC; sensitive stays as submitted\n if (cookie.cpraCategory === 'sale' || cookie.cpraCategory === 'sharing') {\n effectiveConsent[cookie.id] = 'denied'\n }\n } else if (cookie.listenGpc) {\n effectiveConsent[cookie.id] = 'denied'\n }\n }\n }\n\n const validation = validateConsentInput({ ...input, consentJson: effectiveConsent }, profile)\n if (!validation.valid) throw new Error(validation.errors.join('; '))\n\n const builtConsent = buildConsentValue(\n profileCookies,\n effectiveConsent,\n input.gpcDetected,\n regulation,\n )\n\n let tcfString: string | undefined\n if (this.tcfConfig?.enabled && profileCookies.some(c => c.tcfVendorId)) {\n const gvl = await getGvl()\n const { vendorConsents, purposeConsents } = buildTcfPayload(profileCookies, builtConsent)\n tcfString = encodeTcString({\n cmpId: this.tcfConfig.cmpId,\n cmpVersion: this.tcfConfig.cmpVersion,\n consentScreen: 1,\n consentLanguage: input.locale?.slice(0, 2) ?? 'en',\n vendorListVersion: gvl?.vendorListVersion ?? 0,\n purposeConsents,\n vendorConsents,\n })\n }\n\n let baseInput: CreateConsentInput = {\n ...input,\n tenantId: this.tenantId,\n consentJson: builtConsent,\n profileVersion: profile.version,\n ...(tcfString ? { tcfString } : {}),\n }\n if (this.pluginEngine) baseInput = await this.pluginEngine.runBeforeConsentSave(baseInput)\n\n const existing = await this.consents.get(input.visitorId)\n let record: ConsentDbRecord\n\n if (existing) {\n const updateData = await (this.pluginEngine\n ? this.pluginEngine.runBeforeConsentUpdate({ consentJson: builtConsent, locale: input.locale, gpcDetected: input.gpcDetected })\n : Promise.resolve({ consentJson: builtConsent, locale: input.locale, gpcDetected: input.gpcDetected }))\n record = await this.consents.update(input.visitorId, updateData)\n } else {\n record = await this.consents.create(baseInput)\n }\n\n await this.audit.log({\n tenantId: this.tenantId,\n action: existing ? 'consent.updated' : 'consent.created',\n resourceType: 'consent',\n resourceId: record.id,\n ...(existing != null ? { oldData: existing } : {}),\n newData: record,\n })\n\n if (existing) {\n this.eventBus?.emit('consent.updated', { previous: existing, current: record })\n await this.pluginEngine?.runAfterConsentUpdate(record)\n } else {\n this.eventBus?.emit('consent.created', record)\n await this.pluginEngine?.runAfterConsentSave(record)\n }\n\n return record\n }\n\n async update(visitorId: string, input: UpdateConsentInput): Promise<ConsentDbRecord> {\n const existing = await this.consents.get(visitorId)\n if (!existing) throw new Error(`Consent for visitor ${visitorId} not found`)\n\n const profile = await this.profiles.get(existing.profileId)\n if (!profile) throw new Error(`Profile ${existing.profileId} not found`)\n\n const regulation = profile.profileJson.regulation\n const profileCookies2 = profile.profileJson.cookies ?? []\n const effectiveGpc = input.gpcDetected ?? existing.gpcDetected\n let effectiveConsent = input.consentJson\n if (effectiveGpc && this.compliance?.gpc !== false && regulation !== 'dpdpa') {\n effectiveConsent = { ...effectiveConsent }\n for (const cookie of profileCookies2) {\n if (regulation === 'cpra') {\n if (cookie.cpraCategory === 'sale' || cookie.cpraCategory === 'sharing') {\n effectiveConsent[cookie.id] = 'denied'\n }\n } else if (cookie.listenGpc) {\n effectiveConsent[cookie.id] = 'denied'\n }\n }\n }\n\n const builtConsent = buildConsentValue(\n profileCookies2,\n effectiveConsent,\n effectiveGpc,\n regulation,\n )\n\n const record = await this.consents.update(visitorId, { ...input, consentJson: builtConsent })\n await this.audit.log({\n tenantId: this.tenantId,\n action: 'consent.updated',\n resourceType: 'consent',\n resourceId: record.id,\n oldData: existing,\n newData: record,\n })\n return record\n }\n\n get(visitorId: string): Promise<ConsentDbRecord | null> {\n return this.consents.get(visitorId)\n }\n\n async verify(visitorId: string): Promise<ConsentVerifyResult> {\n const record = await this.consents.get(visitorId)\n if (!record) return { valid: false, reasons: ['profile_version_mismatch'] }\n\n const profile = await this.profiles.get(record.profileId)\n if (!profile) return { valid: false, reasons: ['profile_version_mismatch'] }\n\n return verifyConsent(record, profile)\n }\n\n async erase(visitorId: string): Promise<void> {\n const existing = await this.consents.get(visitorId)\n await this.consents.delete(visitorId)\n await this.visitors.delete(visitorId)\n await this.audit.log({\n tenantId: this.tenantId,\n action: 'consent.erased',\n resourceType: 'consent',\n resourceId: visitorId,\n ...(existing != null ? { oldData: existing } : {}),\n })\n }\n}\n","import type { Visitor, CreateVisitorInput } from '@consenti/types'\nimport { hashIp, hashUserAgent } from '../utils/crypto'\nimport type { VisitorRepo } from '../repositories/visitor.repo'\n\nexport class VisitorService {\n constructor(\n private visitors: VisitorRepo,\n private tenantId: string = 'default',\n ) {}\n\n async upsert(data: {\n visitorId: string\n ip?: string\n userAgent?: string\n country?: string\n region?: string\n city?: string\n }): Promise<Visitor> {\n const existing = await this.visitors.get(data.visitorId)\n if (existing) {\n return this.visitors.update(data.visitorId, {\n ...(data.country != null ? { country: data.country } : {}),\n ...(data.region != null ? { region: data.region } : {}),\n ...(data.city != null ? { city: data.city } : {}),\n })\n }\n const input: CreateVisitorInput = {\n tenantId: this.tenantId,\n visitorId: data.visitorId,\n ...(data.country != null ? { country: data.country } : {}),\n ...(data.region != null ? { region: data.region } : {}),\n ...(data.city != null ? { city: data.city } : {}),\n ...(data.ip ? { ipHash: hashIp(data.ip) } : {}),\n ...(data.userAgent ? { userAgentHash: hashUserAgent(data.userAgent) } : {}),\n }\n return this.visitors.create(input)\n }\n}\n","import type { SafeAdminUser, AdminUser, UpdateUserInput } from '@consenti/types'\nimport { hashPassword } from '../utils/crypto'\nimport type { UserRepo } from '../repositories/user.repo'\nimport type { AuditRepo } from '../repositories/audit.repo'\n\nexport class UserService {\n constructor(\n private users: UserRepo,\n private audit: AuditRepo,\n private tenantId: string = 'default',\n ) {}\n\n private safe(user: AdminUser): SafeAdminUser {\n const { passwordHash: _p, ...rest } = user\n return rest\n }\n\n async create(\n input: { name: string; email: string; password: string; roleId?: string },\n actorId?: string,\n ): Promise<SafeAdminUser> {\n const user = await this.users.create({\n tenantId: this.tenantId,\n name: input.name,\n email: input.email,\n passwordHash: hashPassword(input.password),\n })\n if (input.roleId) await this.users.assignRole(user.id, input.roleId)\n await this.audit.log({\n tenantId: this.tenantId,\n ...(actorId != null ? { userId: actorId } : {}),\n action: 'user.created',\n resourceType: 'user',\n resourceId: user.id,\n newData: this.safe(user),\n })\n return this.safe(user)\n }\n\n async update(\n id: string,\n input: { name?: string; email?: string; isActive?: boolean; password?: string },\n actorId?: string,\n ): Promise<SafeAdminUser> {\n const existing = await this.users.getById(id)\n if (!existing) throw new Error(`User ${id} not found`)\n const data: UpdateUserInput = {}\n if (input.name != null) data.name = input.name\n if (input.email != null) data.email = input.email\n if (input.isActive != null) data.isActive = input.isActive\n if (input.password) data.passwordHash = hashPassword(input.password)\n const updated = await this.users.update(id, data)\n await this.audit.log({\n tenantId: this.tenantId,\n ...(actorId != null ? { userId: actorId } : {}),\n action: 'user.updated',\n resourceType: 'user',\n resourceId: id,\n oldData: this.safe(existing),\n newData: this.safe(updated),\n })\n return this.safe(updated)\n }\n\n async delete(id: string, actorId?: string): Promise<void> {\n const existing = await this.users.getById(id)\n await this.users.delete(id)\n await this.audit.log({\n tenantId: this.tenantId,\n ...(actorId != null ? { userId: actorId } : {}),\n action: 'user.deleted',\n resourceType: 'user',\n resourceId: id,\n ...(existing != null ? { oldData: this.safe(existing) } : {}),\n })\n }\n\n async get(id: string): Promise<SafeAdminUser | null> {\n const user = await this.users.getById(id)\n return user ? this.safe(user) : null\n }\n\n async list(): Promise<SafeAdminUser[]> {\n const users = await this.users.list(this.tenantId)\n return users.map(u => this.safe(u))\n }\n\n getRoles(userId: string, tenantId?: string) { return this.users.getRoles(userId, tenantId) }\n assignRole(userId: string, roleId: string, tenantId?: string) { return this.users.assignRole(userId, roleId, tenantId) }\n revokeRole(userId: string, roleId: string, tenantId?: string) { return this.users.revokeRole(userId, roleId, tenantId) }\n}\n","import type { StorageAdapter, AdminUser } from '@consenti/types'\nimport { hashPassword, verifyPassword, signJwt, verifyJwt } from '../utils/crypto'\n\nconst LOCKOUT_WINDOW_MS = 15 * 60_000\nconst MAX_FAILED_ATTEMPTS = 5\n\nexport class LocalAuth {\n private loginAttempts = new Map<string, { count: number; resetAt: number }>()\n\n constructor(\n private storage: StorageAdapter,\n private secret: string,\n ) {\n setInterval(() => {\n const now = Date.now()\n for (const [key, entry] of this.loginAttempts) {\n if (now >= entry.resetAt) this.loginAttempts.delete(key)\n }\n }, LOCKOUT_WINDOW_MS).unref()\n }\n\n async bootstrap(email: string, password: string): Promise<AdminUser | null> {\n const count = await this.storage.countUsers('default')\n if (count > 0) return null\n if (password.length < 12) {\n throw new Error('[Consenti] bootstrap: admin password must be at least 12 characters')\n }\n if (password.length < 16) {\n console.warn('[Consenti] bootstrap: admin password is shorter than 16 characters — consider using a longer password')\n }\n const passwordHash = hashPassword(password)\n const user = await this.storage.createUser({\n tenantId: 'default',\n name: 'Admin',\n email,\n passwordHash,\n })\n await this.storage.assignRole(user.id, 'role_super_admin')\n return user\n }\n\n async login(email: string, password: string): Promise<string | null> {\n const now = Date.now()\n const attempts = this.loginAttempts.get(email)\n if (attempts && now < attempts.resetAt && attempts.count >= MAX_FAILED_ATTEMPTS) return null\n\n const user = await this.storage.getUserByEmail(email)\n if (!user || !user.isActive || !verifyPassword(password, user.passwordHash)) {\n const entry = this.loginAttempts.get(email)\n if (!entry || now >= entry.resetAt) {\n this.loginAttempts.set(email, { count: 1, resetAt: now + LOCKOUT_WINDOW_MS })\n } else {\n entry.count += 1\n }\n return null\n }\n\n this.loginAttempts.delete(email)\n const roles = await this.storage.getUserRoles(user.id)\n const permSets = await Promise.all(roles.map(r => this.storage.getPermissionsForRole(r.id)))\n const permissions = [...new Set(permSets.flat().map(p => p.name))]\n return signJwt(\n { sub: user.id, email: user.email, roles: roles.map(r => r.name), permissions },\n this.secret,\n )\n }\n\n signToken(payload: { sub: string; email: string; roles: string[]; permissions: string[] }): string {\n return signJwt(payload, this.secret)\n }\n\n verify(token: string): Record<string, unknown> | null {\n return verifyJwt(token, this.secret)\n }\n\n async getUser(token: string): Promise<AdminUser | null> {\n const payload = this.verify(token)\n if (!payload) return null\n const id = payload['sub']\n if (typeof id !== 'string') return null\n return this.storage.getUserById(id)\n }\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\n\nexport class PayloadTooLargeError extends Error {\n constructor() { super('Payload Too Large') }\n}\n\nexport function getIp(req: IncomingMessage, trustedProxies?: string[]): string {\n const remoteIp = req.socket?.remoteAddress ?? ''\n if (!trustedProxies?.length) return remoteIp\n if (!trustedProxies.includes(remoteIp)) return remoteIp\n const fwd = req.headers['x-forwarded-for']\n if (typeof fwd === 'string') return fwd.split(',')[0]?.trim() ?? remoteIp\n if (Array.isArray(fwd)) return fwd[0]?.trim() ?? remoteIp\n return remoteIp\n}\n\nexport function json(status: number, data: unknown): Response {\n return new Response(JSON.stringify(data), {\n status,\n headers: { 'Content-Type': 'application/json' },\n })\n}\n\nexport async function parseJsonBody<T = unknown>(request: Request): Promise<T | null> {\n const ct = request.headers.get('content-type') ?? ''\n if (!ct.includes('application/json')) return null\n try {\n return await request.json() as T\n } catch {\n return null\n }\n}\n\nexport function getQueryParam(url: URL, key: string): string | undefined {\n const val = url.searchParams.get(key)\n return val ?? undefined\n}\n\nexport function getQueryInt(url: URL, key: string, fallback: number): number {\n const val = url.searchParams.get(key)\n if (!val) return fallback\n const n = parseInt(val, 10)\n return isNaN(n) ? fallback : n\n}\n\nexport async function nodeRequestToFetch(\n req: IncomingMessage,\n maxBodyBytes = 1_048_576,\n trustedProxies?: string[],\n): Promise<Request> {\n const rawProto = req.headers['x-forwarded-proto']\n const proto = rawProto === 'https' ? 'https' : 'http'\n const host = req.headers['host'] ?? 'localhost'\n const url = new URL(req.url ?? '/', `${proto}://${host}`)\n\n const headers = new Headers()\n for (const [key, value] of Object.entries(req.headers)) {\n if (!value) continue\n if (Array.isArray(value)) {\n for (const v of value) headers.append(key, v)\n } else {\n headers.set(key, value)\n }\n }\n headers.set('x-real-ip', getIp(req, trustedProxies))\n\n let body: BodyInit | null = null\n const method = (req.method ?? 'GET').toUpperCase()\n if (method !== 'GET' && method !== 'HEAD') {\n const chunks: Buffer[] = []\n let totalBytes = 0\n for await (const chunk of req) {\n totalBytes += (chunk as Buffer).length\n if (totalBytes > maxBodyBytes) throw new PayloadTooLargeError()\n chunks.push(chunk as Buffer)\n }\n if (chunks.length > 0) body = Buffer.concat(chunks)\n }\n\n return new Request(url.toString(), { method, headers, body })\n}\n\nexport async function fetchResponseToNode(response: Response, res: ServerResponse): Promise<void> {\n res.statusCode = response.status\n const setCookies: string[] =\n typeof (response.headers as { getSetCookie?: () => string[] }).getSetCookie === 'function'\n ? (response.headers as unknown as { getSetCookie: () => string[] }).getSetCookie()\n : (response.headers.get('set-cookie') ? [response.headers.get('set-cookie')!] : [])\n response.headers.forEach((value, key) => {\n if (key.toLowerCase() === 'set-cookie') return\n res.setHeader(key, value)\n })\n for (const cookie of setCookies) {\n res.appendHeader('set-cookie', cookie)\n }\n if (response.body) {\n const reader = response.body.getReader()\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n res.write(Buffer.from(value))\n }\n } finally {\n reader.releaseLock()\n }\n res.end()\n } else {\n res.end()\n }\n}\n","export function errorResponse(status: number, message: string, details?: unknown): Response {\n const body: Record<string, unknown> = { error: message }\n if (details != null && process.env['NODE_ENV'] !== 'production') {\n body['details'] = details\n }\n return new Response(JSON.stringify(body), {\n status,\n headers: { 'Content-Type': 'application/json' },\n })\n}\n\nexport async function withErrorHandler(fn: () => Promise<Response>): Promise<Response> {\n try {\n return await fn()\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Internal Server Error'\n return errorResponse(500, 'Internal Server Error',\n process.env['NODE_ENV'] !== 'production' ? message : undefined)\n }\n}\n","import type { ProfileService } from '../../services/profile.service'\nimport { json } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\n\nexport function buildProfileRoutes(profiles: ProfileService) {\n return {\n 'GET /profiles/:id': async (_request: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const id = params['id']\n if (!id) return errorResponse(400, 'Missing profile id')\n const result = await profiles.getResolved(id)\n if (!result) return errorResponse(404, 'Profile not found')\n return json(200, result)\n }),\n\n 'GET /profiles/:id/:locale': async (_request: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const id = params['id']\n const locale = params['locale']\n if (!id) return errorResponse(400, 'Missing profile id')\n if (!locale) return errorResponse(400, 'Missing locale')\n const result = await profiles.getResolved(id, locale)\n if (!result) return errorResponse(404, 'Profile not found')\n return json(200, result)\n }),\n }\n}\n","import type { ConsentDbRecord, ConsentValue } from '@consenti/types'\n\nfunction buildCookieValue(consentJson: ConsentValue, timestamp: string): string {\n const entries = Object.entries(consentJson)\n .map(([k, v]) => `${k}:${v}`)\n .join('|')\n return `ConsentTimestamp:${timestamp}::${entries}`\n}\n\nexport function buildConsentSetCookie(record: ConsentDbRecord): string {\n const name = `consenti_${record.visitorId}_${record.profileId}`\n const value = buildCookieValue(record.consentJson, record.createdAt)\n const secure = process.env['NODE_ENV'] === 'production' ? '; Secure' : ''\n return `${name}=${value}; SameSite=Lax${secure}; Path=/; Max-Age=31536000`\n}\n\nexport function buildExpireSetCookie(visitorId: string, profileId: string): string {\n const name = `consenti_${visitorId}_${profileId}`\n const secure = process.env['NODE_ENV'] === 'production' ? '; Secure' : ''\n return `${name}=; SameSite=Lax${secure}; Path=/; Max-Age=0`\n}\n","function matchesAllowedOrigin(origin: string, allowedOrigins: string[]): boolean {\n let hostname: string\n try {\n hostname = new URL(origin).hostname\n } catch {\n return false\n }\n return allowedOrigins.some(pattern => {\n if (pattern.startsWith('*.')) {\n const suffix = pattern.slice(1) // '.example.com'\n return hostname === pattern.slice(2) || hostname.endsWith(suffix)\n }\n return hostname === pattern\n })\n}\n\nexport function buildCorsHeaders(origin: string | null, allowedOrigins?: string[]): Record<string, string> {\n let allowOrigin = origin ?? '*'\n if (allowedOrigins && allowedOrigins.length > 0 && origin) {\n allowOrigin = matchesAllowedOrigin(origin, allowedOrigins) ? origin : 'null'\n }\n return {\n 'Access-Control-Allow-Origin': allowOrigin,\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n 'Access-Control-Max-Age': '86400',\n }\n}\n\nexport function handleCors(request: Request): Response | null {\n if (request.method === 'OPTIONS') {\n const origin = request.headers.get('origin')\n return new Response(null, {\n status: 204,\n headers: buildCorsHeaders(origin),\n })\n }\n return null\n}\n\nexport function withCors(response: Response, request: Request): Response {\n const origin = request.headers.get('origin')\n const cors = buildCorsHeaders(origin)\n const newHeaders = new Headers(response.headers)\n for (const [k, v] of Object.entries(cors)) newHeaders.set(k, v)\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: newHeaders,\n })\n}\n\nexport function checkOriginAllowed(request: Request, allowedOrigins: string[]): boolean {\n if (allowedOrigins.length === 0) return true\n const origin = request.headers.get('origin')\n if (!origin) return true // non-browser / server-side calls always allowed\n return matchesAllowedOrigin(origin, allowedOrigins)\n}\n\nexport function addSecurityHeaders(res: Response): Response {\n const h = new Headers(res.headers)\n h.set('X-Content-Type-Options', 'nosniff')\n h.set('X-Frame-Options', 'DENY')\n h.set('Referrer-Policy', 'no-referrer')\n h.set('Permissions-Policy', 'interest-cohort=()')\n return new Response(res.body, { status: res.status, statusText: res.statusText, headers: h })\n}\n","import type { CreateConsentInput, UpdateConsentInput, ConsentValue } from '@consenti/types'\n\nexport interface ValidationResult {\n valid: boolean\n error?: string\n}\n\nconst VALID_STATUSES = new Set(['granted', 'denied', 'objected'])\n\nfunction validateConsentJsonValues(consentJson: unknown): ValidationResult {\n const entries = Object.entries(consentJson as Record<string, unknown>)\n for (const [key, val] of entries) {\n if (!key) return { valid: false, error: 'consentJson keys must be non-empty strings' }\n if (!VALID_STATUSES.has(val as string)) {\n return { valid: false, error: `consentJson value \"${String(val)}\" is invalid; must be granted, denied, or objected` }\n }\n }\n return { valid: true }\n}\n\nexport function validateCreateConsent(body: unknown): ValidationResult {\n if (!body || typeof body !== 'object') return { valid: false, error: 'Request body must be a JSON object' }\n const b = body as Record<string, unknown>\n if (typeof b['profileId'] !== 'string' || !b['profileId']) return { valid: false, error: 'profileId is required' }\n if (!b['consentJson'] || typeof b['consentJson'] !== 'object' || Array.isArray(b['consentJson'])) {\n return { valid: false, error: 'consentJson must be an object' }\n }\n return validateConsentJsonValues(b['consentJson'])\n}\n\nexport function validateUpdateConsent(body: unknown): ValidationResult {\n if (!body || typeof body !== 'object') return { valid: false, error: 'Request body must be a JSON object' }\n const b = body as Record<string, unknown>\n if (!b['consentJson'] || typeof b['consentJson'] !== 'object' || Array.isArray(b['consentJson'])) {\n return { valid: false, error: 'consentJson must be an object' }\n }\n return validateConsentJsonValues(b['consentJson'])\n}\n\nexport function castCreateConsent(body: Record<string, unknown>, visitorId: string, tenantId: string): CreateConsentInput {\n return {\n tenantId,\n visitorId,\n profileId: body['profileId'] as string,\n profileVersion: typeof body['profileVersion'] === 'number' ? body['profileVersion'] : 1,\n locale: typeof body['locale'] === 'string' ? body['locale'] : 'en',\n consentJson: body['consentJson'] as ConsentValue,\n gpcDetected: Boolean(body['gpcDetected']),\n source: (body['source'] as CreateConsentInput['source']) ?? 'banner',\n }\n}\n\nexport function castUpdateConsent(body: Record<string, unknown>): UpdateConsentInput {\n const result: UpdateConsentInput = {\n consentJson: body['consentJson'] as ConsentValue,\n }\n if (typeof body['locale'] === 'string') result.locale = body['locale']\n if (body['gpcDetected'] != null) result.gpcDetected = Boolean(body['gpcDetected'])\n return result\n}\n","import type { ConsentService } from '../../services/consent.service'\nimport type { VisitorService } from '../../services/visitor.service'\nimport type { ProfileService } from '../../services/profile.service'\nimport { parseJsonBody } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { buildConsentSetCookie, buildExpireSetCookie } from '../../utils/cookie'\nimport { checkOriginAllowed } from '../../middleware/cors.middleware'\nimport {\n validateCreateConsent, validateUpdateConsent,\n castCreateConsent, castUpdateConsent,\n} from '../../validators/consent.validator'\nimport { randomUUID } from '../../utils/crypto'\n\n// Verify that the request's cookie contains a consenti_<visitorId>_* token,\n// proving the caller is the actual visitor who originally submitted consent.\nfunction assertVisitorOwnership(request: Request, visitorId: string): Response | null {\n const cookieHeader = request.headers.get('cookie') ?? ''\n const prefix = `consenti_${visitorId}_`\n const owned = cookieHeader.split(';').some(c => {\n const trimmed = c.trim()\n if (!trimmed.startsWith(prefix)) return false\n const val = trimmed.slice(trimmed.indexOf('=') + 1)\n return val.startsWith('ConsentTimestamp:')\n })\n if (!owned) return errorResponse(403, 'Forbidden')\n return null\n}\n\nexport function buildConsentRoutes(\n consents: ConsentService,\n visitors: VisitorService,\n profiles: ProfileService,\n resolveTenantId: (req: Request) => Promise<string> = async () => 'default',\n) {\n return {\n 'POST /consent': async (request: Request, _params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const body = await parseJsonBody(request)\n const validation = validateCreateConsent(body)\n if (!validation.valid) return errorResponse(400, validation.error ?? 'Invalid request')\n\n const b = body as Record<string, unknown>\n const profileId = typeof b['profileId'] === 'string' ? b['profileId'] : null\n if (!profileId) return errorResponse(400, 'profileId is required')\n\n // Layer 1: verify the profileId is real — blocks all requests with unknown profiles\n const profile = await profiles.get(profileId)\n if (!profile) return errorResponse(404, 'Profile not found')\n\n // Layer 3: enforce the profile's allowed-domains list\n const pjConfig = profile.profileJson as { allowedOrigins?: string[] }\n const allowedOrigins = pjConfig.allowedOrigins ?? []\n if (!checkOriginAllowed(request, allowedOrigins)) {\n return errorResponse(403, 'Origin not allowed for this profile')\n }\n\n const visitorId = typeof b['visitorId'] === 'string' ? b['visitorId'] : randomUUID()\n const ip = request.headers.get('x-real-ip') ?? ''\n const ua = request.headers.get('user-agent') ?? ''\n const tenantId = await resolveTenantId(request)\n\n await visitors.upsert({ visitorId, ip, userAgent: ua })\n const input = castCreateConsent(b, visitorId, tenantId)\n const record = await consents.create(input)\n\n const setCookie = buildConsentSetCookie(record)\n return new Response(JSON.stringify(record), {\n status: 201,\n headers: {\n 'Content-Type': 'application/json',\n 'Set-Cookie': setCookie,\n },\n })\n }),\n\n 'PUT /consent/:visitorId': async (request: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const visitorId = params['visitorId']\n if (!visitorId) return errorResponse(400, 'Missing visitorId')\n\n // Layer 2: only the visitor's own browser may update their consent\n const ownershipError = assertVisitorOwnership(request, visitorId)\n if (ownershipError) return ownershipError\n\n const body = await parseJsonBody(request)\n const validation = validateUpdateConsent(body)\n if (!validation.valid) return errorResponse(400, validation.error ?? 'Invalid request')\n\n const input = castUpdateConsent(body as Record<string, unknown>)\n const record = await consents.update(visitorId, input)\n\n const setCookie = buildConsentSetCookie(record)\n return new Response(JSON.stringify(record), {\n status: 200,\n headers: {\n 'Content-Type': 'application/json',\n 'Set-Cookie': setCookie,\n },\n })\n }),\n\n 'GET /consent/:visitorId': async (request: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const visitorId = params['visitorId']\n if (!visitorId) return errorResponse(400, 'Missing visitorId')\n\n // Layer 2: only the visitor's own browser may read their consent\n const ownershipError = assertVisitorOwnership(request, visitorId)\n if (ownershipError) return ownershipError\n\n const record = await consents.get(visitorId)\n if (!record) return errorResponse(404, 'Consent not found')\n return new Response(JSON.stringify(record), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n })\n }),\n\n 'GET /consent/:visitorId/verify': async (request: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const visitorId = params['visitorId']\n if (!visitorId) return errorResponse(400, 'Missing visitorId')\n\n // Layer 2: cookie ownership (browser calls); server-side callers use admin auth upstream\n const ownershipError = assertVisitorOwnership(request, visitorId)\n if (ownershipError) return ownershipError\n\n const result = await consents.verify(visitorId)\n return new Response(JSON.stringify(result), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n })\n }),\n\n 'DELETE /consent/:visitorId': async (request: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const visitorId = params['visitorId']\n if (!visitorId) return errorResponse(400, 'Missing visitorId')\n\n // Layer 2: only the visitor's own browser may erase their consent\n const ownershipError = assertVisitorOwnership(request, visitorId)\n if (ownershipError) return ownershipError\n\n const existing = await consents.get(visitorId)\n await consents.erase(visitorId)\n const headers: Record<string, string> = { 'Content-Type': 'application/json' }\n if (existing) {\n headers['Set-Cookie'] = buildExpireSetCookie(visitorId, existing.profileId)\n }\n return new Response(JSON.stringify({ success: true }), { status: 200, headers })\n }),\n }\n}\n","import { randomBytes } from 'node:crypto'\nimport type { StorageAdapter, AuthConfig } from '@consenti/types'\nimport { json, parseJsonBody } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate } from '../../middleware/auth.middleware'\nimport type { RateLimiter } from '../../middleware/rate-limit.middleware'\nimport type { LocalAuth } from '../../auth/local.auth'\nimport {\n generatePkce, discoverOidcEndpoints, buildAuthorizationUrl,\n exchangeOidcCode, verifyOidcIdToken, extractEmailFromClaims,\n extractRolesFromClaims, storePkceState, consumePkceState,\n} from '../../auth/oidc.auth'\nimport { buildSamlMetadataXml, validateSamlResponse } from '../../auth/saml.auth'\nimport { generateTotpSecret, verifyTotp, totpQrUrl } from '../../auth/totp'\n\nfunction base64url(buf: Buffer): string {\n return buf.toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '')\n}\n\nexport function buildAdminAuthRoutes(\n localAuth: LocalAuth,\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n authLimiter?: RateLimiter | null,\n) {\n function checkAuthLimit(req: Request): Response | null {\n if (!authLimiter) return null\n const ip = req.headers.get('x-real-ip') ?? ''\n if (!authLimiter.checkRequest(ip)) return errorResponse(429, 'Too Many Requests')\n return null\n }\n\n return {\n 'POST /auth/login': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const limited = checkAuthLimit(req)\n if (limited) return limited\n if (authConfig.mode !== 'local') return errorResponse(400, 'Login not available in this auth mode')\n const body = await parseJsonBody(req)\n if (!body || typeof body !== 'object') return errorResponse(400, 'Invalid body')\n const b = body as Record<string, unknown>\n if (typeof b['email'] !== 'string' || typeof b['password'] !== 'string') {\n return errorResponse(400, 'email and password are required')\n }\n const token = await localAuth.login(b['email'], b['password'])\n if (!token) return errorResponse(401, 'Invalid credentials')\n return json(200, { token })\n }),\n\n 'GET /auth/me': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const user = await authenticate(req, storage, authConfig, secret)\n if (!user) return errorResponse(401, 'Unauthorized')\n const dbUser = await storage.getUserById(user.sub)\n if (!dbUser) return errorResponse(401, 'User not found')\n const roles = await storage.getUserRoles(dbUser.id)\n return json(200, {\n id: dbUser.id,\n email: dbUser.email,\n name: dbUser.name,\n isActive: dbUser.isActive,\n totpEnabled: dbUser.totpEnabled ?? false,\n roles: roles.map(r => r.name),\n permissions: user.permissions,\n })\n }),\n\n 'POST /auth/logout': async (_req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => json(200, { success: true })),\n\n // ── OIDC ────────────────────────────────────────────────────────────────────\n\n 'GET /auth/oidc/authorize': async (_req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n if (authConfig.mode !== 'oidc' || !authConfig.oidc) return errorResponse(400, 'OIDC not configured')\n const endpoints = await discoverOidcEndpoints(authConfig.oidc.issuer)\n const state = base64url(randomBytes(16))\n const nonce = base64url(randomBytes(16))\n const { verifier, challenge } = generatePkce()\n storePkceState(state, verifier, nonce)\n const url = buildAuthorizationUrl(authConfig.oidc, endpoints.authorization_endpoint, state, nonce, challenge)\n return new Response(null, { status: 302, headers: { Location: url } })\n }),\n\n 'GET /auth/oidc/callback': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n if (authConfig.mode !== 'oidc' || !authConfig.oidc) return errorResponse(400, 'OIDC not configured')\n const url = new URL(req.url)\n const code = url.searchParams.get('code')\n const state = url.searchParams.get('state')\n if (!code || !state) return errorResponse(400, 'Missing code or state')\n const pkce = consumePkceState(state)\n if (!pkce) return errorResponse(400, 'Invalid or expired state')\n const endpoints = await discoverOidcEndpoints(authConfig.oidc.issuer)\n const tokens = await exchangeOidcCode(authConfig.oidc, endpoints.token_endpoint, code, pkce.verifier)\n const claims = await verifyOidcIdToken(tokens.id_token, endpoints.jwks_uri)\n const email = extractEmailFromClaims(claims, authConfig.oidc.claimsMapping)\n const roles = extractRolesFromClaims(claims, authConfig.oidc.claimsMapping)\n // Upsert admin user from OIDC claims\n let user = await storage.getUserByEmail(email)\n if (!user) {\n user = await storage.createUser({ tenantId: 'default', name: email, email, passwordHash: '' })\n }\n if (roles.length > 0) {\n const allRoles = await storage.getRoles('default')\n for (const roleName of roles) {\n const role = allRoles.find(r => r.name === roleName)\n if (role) await storage.assignRole(user.id, role.id).catch(() => {})\n }\n }\n const userRoles = await storage.getUserRoles(user.id)\n const permissions: string[] = []\n for (const role of userRoles) {\n const perms = await storage.getPermissionsForRole(role.id)\n permissions.push(...perms.map(p => p.name))\n }\n const token = localAuth.signToken({\n sub: user.id, email: user.email,\n roles: userRoles.map(r => r.name),\n permissions: [...new Set(permissions)],\n })\n return json(200, { token })\n }),\n\n // ── SAML ────────────────────────────────────────────────────────────────────\n\n 'GET /auth/saml/metadata': async (_req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n if (authConfig.mode !== 'saml' || !authConfig.saml) return errorResponse(400, 'SAML not configured')\n const xml = buildSamlMetadataXml(authConfig.saml)\n return new Response(xml, { status: 200, headers: { 'Content-Type': 'application/xml' } })\n }),\n\n 'POST /auth/saml/acs': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const limited = checkAuthLimit(req)\n if (limited) return limited\n if (authConfig.mode !== 'saml' || !authConfig.saml) return errorResponse(400, 'SAML not configured')\n const params = new URLSearchParams(await req.text())\n const samlResponse = params.get('SAMLResponse')\n if (typeof samlResponse !== 'string') return errorResponse(400, 'Missing SAMLResponse')\n const info = await validateSamlResponse(samlResponse, authConfig.saml)\n if (!info) return errorResponse(401, 'SAML validation failed')\n let user = await storage.getUserByEmail(info.email)\n if (!user) {\n user = await storage.createUser({ tenantId: 'default', name: info.email, email: info.email, passwordHash: '' })\n }\n const userRoles = await storage.getUserRoles(user.id)\n const permissions: string[] = []\n for (const role of userRoles) {\n const perms = await storage.getPermissionsForRole(role.id)\n permissions.push(...perms.map(p => p.name))\n }\n const token = localAuth.signToken({\n sub: user.id, email: user.email,\n roles: userRoles.map(r => r.name),\n permissions: [...new Set(permissions)],\n })\n return json(200, { token })\n }),\n\n // ── TOTP ────────────────────────────────────────────────────────────────────\n\n 'POST /auth/totp/setup': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const user = await authenticate(req, storage, authConfig, secret)\n if (!user) return errorResponse(401, 'Unauthorized')\n const dbUser = await storage.getUserById(user.sub)\n if (!dbUser) return errorResponse(401, 'User not found')\n const totpSecret = generateTotpSecret()\n const qrUrl = totpQrUrl(totpSecret, dbUser.email)\n await storage.updateUser(dbUser.id, { totpSecret, totpEnabled: false })\n return json(200, { qrUrl, message: 'Scan QR code, then verify with POST /auth/totp/verify' })\n }),\n\n 'POST /auth/totp/verify': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const limited = checkAuthLimit(req)\n if (limited) return limited\n const user = await authenticate(req, storage, authConfig, secret)\n if (!user) return errorResponse(401, 'Unauthorized')\n const dbUser = await storage.getUserById(user.sub)\n if (!dbUser) return errorResponse(401, 'User not found')\n if (!dbUser.totpSecret) return errorResponse(400, 'TOTP not set up — call POST /auth/totp/setup first')\n const body = await parseJsonBody(req)\n if (!body || typeof body !== 'object') return errorResponse(400, 'Invalid body')\n const b = body as Record<string, unknown>\n if (typeof b['token'] !== 'string') return errorResponse(400, 'token is required')\n if (!verifyTotp(dbUser.totpSecret, b['token'])) return errorResponse(400, 'Invalid TOTP token')\n await storage.updateUser(dbUser.id, { totpEnabled: true })\n return json(200, { success: true, message: 'TOTP enabled successfully' })\n }),\n\n 'POST /auth/totp/disable': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const user = await authenticate(req, storage, authConfig, secret)\n if (!user) return errorResponse(401, 'Unauthorized')\n const dbUser = await storage.getUserById(user.sub)\n if (!dbUser) return errorResponse(401, 'User not found')\n await storage.updateUser(dbUser.id, { totpSecret: null, totpEnabled: false })\n return json(200, { success: true, message: 'TOTP disabled' })\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig } from '@consenti/types'\nimport { verifyJwt } from '../utils/crypto'\nimport { errorResponse } from './error.middleware'\n\nexport interface AuthenticatedUser {\n sub: string\n email: string\n roles: string[]\n permissions: string[]\n}\n\nexport async function authenticate(\n req: Request,\n storage: StorageAdapter,\n config: AuthConfig,\n secret: string,\n): Promise<AuthenticatedUser | null> {\n const auth = req.headers.get('authorization')\n const token = auth?.startsWith('Bearer ') ? auth.slice(7) : null\n if (!token) return null\n\n if (config.mode === 'local' || config.mode === 'jwt') {\n const payload = verifyJwt(token, secret)\n if (!payload) return null\n const sub = payload['sub']\n const email = payload['email']\n const roles = payload['roles']\n const permissions = payload['permissions']\n if (typeof sub !== 'string' || typeof email !== 'string') return null\n return {\n sub,\n email,\n roles: Array.isArray(roles) ? (roles as string[]) : [],\n permissions: Array.isArray(permissions) ? (permissions as string[]) : [],\n }\n }\n\n if (config.mode === 'custom' && config.validateUser) {\n const user = await config.validateUser(req)\n if (!user) return null\n const roles = await storage.getUserRoles(user.id)\n const permSets = await Promise.all(roles.map(r => storage.getPermissionsForRole(r.id)))\n const permissions = [...new Set(permSets.flat().map(p => p.name))]\n return {\n sub: user.id,\n email: user.email,\n roles: roles.map(r => r.name),\n permissions,\n }\n }\n\n return null\n}\n\nexport function authError(\n user: AuthenticatedUser | null,\n permission?: string,\n): Response | null {\n if (!user) return errorResponse(401, 'Unauthorized')\n if (permission && !user.permissions.includes(permission)) return errorResponse(403, 'Forbidden')\n return null\n}\n","import { randomBytes, createHash } from 'node:crypto'\nimport type { OidcConfig } from '@consenti/types'\n\nfunction base64url(buf: Buffer): string {\n return buf.toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '')\n}\n\nfunction base64urlDecode(s: string): string {\n return Buffer.from(s.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf8')\n}\n\nexport interface PkceChallenge {\n verifier: string\n challenge: string\n}\n\nexport function generatePkce(): PkceChallenge {\n const verifier = base64url(randomBytes(32))\n const challenge = base64url(createHash('sha256').update(verifier).digest())\n return { verifier, challenge }\n}\n\ninterface OidcEndpoints {\n authorization_endpoint: string\n token_endpoint: string\n userinfo_endpoint?: string\n jwks_uri: string\n}\n\nexport async function discoverOidcEndpoints(issuer: string): Promise<OidcEndpoints> {\n const res = await fetch(`${issuer}/.well-known/openid-configuration`, {\n signal: AbortSignal.timeout(10_000),\n })\n if (!res.ok) throw new Error(`OIDC discovery failed for ${issuer}: ${res.status}`)\n return res.json() as Promise<OidcEndpoints>\n}\n\nexport function buildAuthorizationUrl(\n config: OidcConfig,\n authorizationEndpoint: string,\n state: string,\n nonce: string,\n codeChallenge: string,\n): string {\n const params = new URLSearchParams({\n response_type: 'code',\n client_id: config.clientId,\n redirect_uri: config.redirectUri,\n scope: 'openid email profile',\n state,\n nonce,\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n })\n return `${authorizationEndpoint}?${params.toString()}`\n}\n\ninterface TokenResponse {\n id_token: string\n access_token: string\n token_type: string\n expires_in?: number\n}\n\nexport async function exchangeOidcCode(\n config: OidcConfig,\n tokenEndpoint: string,\n code: string,\n codeVerifier: string,\n): Promise<TokenResponse> {\n const body = new URLSearchParams({\n grant_type: 'authorization_code',\n client_id: config.clientId,\n client_secret: config.clientSecret,\n redirect_uri: config.redirectUri,\n code,\n code_verifier: codeVerifier,\n })\n const res = await fetch(tokenEndpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: body.toString(),\n signal: AbortSignal.timeout(10_000),\n })\n if (!res.ok) {\n const err = await res.text()\n throw new Error(`OIDC token exchange failed: ${err}`)\n }\n return res.json() as Promise<TokenResponse>\n}\n\nexport interface OidcClaims {\n sub: string\n email?: string\n name?: string\n [key: string]: unknown\n}\n\nexport async function verifyOidcIdToken(idToken: string, jwksUri: string): Promise<OidcClaims> {\n const parts = idToken.split('.')\n if (parts.length !== 3) throw new Error('Invalid ID token format')\n\n const header = JSON.parse(base64urlDecode(parts[0]!)) as { kid?: string; alg?: string }\n const alg = header.alg ?? 'RS256'\n\n const res = await fetch(jwksUri, { signal: AbortSignal.timeout(10_000) })\n if (!res.ok) throw new Error(`Failed to fetch JWKS: ${res.status}`)\n type JwkEntry = JsonWebKey & { kid?: string; use?: string }\n const jwks = await res.json() as { keys: JwkEntry[] }\n\n const jwk: JwkEntry | undefined = header.kid\n ? jwks.keys.find(k => k.kid === header.kid)\n : (jwks.keys.find(k => k.use === 'sig') ?? jwks.keys[0])\n if (!jwk) throw new Error('No matching key in JWKS')\n\n let cryptoKey: CryptoKey\n if (alg === 'RS256' || alg === 'RS384' || alg === 'RS512') {\n const hashName = alg === 'RS256' ? 'SHA-256' : alg === 'RS384' ? 'SHA-384' : 'SHA-512'\n cryptoKey = await globalThis.crypto.subtle.importKey(\n 'jwk', jwk, { name: 'RSASSA-PKCS1-v1_5', hash: { name: hashName } }, false, ['verify'],\n )\n } else if (alg === 'ES256' || alg === 'ES384' || alg === 'ES512') {\n const namedCurve = alg === 'ES256' ? 'P-256' : alg === 'ES384' ? 'P-384' : 'P-521'\n cryptoKey = await globalThis.crypto.subtle.importKey(\n 'jwk', jwk, { name: 'ECDSA', namedCurve }, false, ['verify'],\n )\n } else {\n throw new Error(`Unsupported OIDC token algorithm: ${alg}`)\n }\n\n const sigInput = new TextEncoder().encode(`${parts[0]}.${parts[1]}`)\n const padding = (4 - (parts[2]!.length % 4)) % 4\n const sigB64 = parts[2]!.replace(/-/g, '+').replace(/_/g, '/') + '='.repeat(padding)\n const sigBytes = Uint8Array.from(atob(sigB64), c => c.charCodeAt(0))\n\n const verifyAlg = alg.startsWith('ES')\n ? { name: 'ECDSA', hash: { name: `SHA-${alg.slice(2)}` } }\n : { name: 'RSASSA-PKCS1-v1_5' }\n\n const valid = await globalThis.crypto.subtle.verify(verifyAlg, cryptoKey, sigBytes, sigInput)\n if (!valid) throw new Error('ID token signature verification failed')\n\n const payload = JSON.parse(base64urlDecode(parts[1]!)) as OidcClaims\n const now = Math.floor(Date.now() / 1000)\n if (typeof payload['exp'] === 'number' && payload['exp'] < now) {\n throw new Error('ID token has expired')\n }\n\n return payload\n}\n\nexport function extractEmailFromClaims(claims: OidcClaims, mapping?: { email?: string }): string {\n const key = mapping?.email ?? 'email'\n const value = claims[key]\n if (typeof value !== 'string') throw new Error('OIDC token missing email claim')\n return value\n}\n\nexport function extractRolesFromClaims(\n claims: OidcClaims,\n mapping?: { roles?: string },\n): string[] {\n const key = mapping?.roles ?? 'consenti_roles'\n const value = claims[key]\n if (!Array.isArray(value)) return []\n return value.filter((v): v is string => typeof v === 'string')\n}\n\n// In-memory PKCE/state store. Replace with Redis or DB for multi-instance deployments.\nconst pendingStates = new Map<string, { verifier: string; nonce: string; expiresAt: number }>()\n\nsetInterval(() => {\n const now = Date.now()\n for (const [key, val] of pendingStates) {\n if (val.expiresAt < now) pendingStates.delete(key)\n }\n}, 5 * 60_000).unref()\n\nexport function storePkceState(state: string, verifier: string, nonce: string): void {\n pendingStates.set(state, { verifier, nonce, expiresAt: Date.now() + 10 * 60_000 })\n}\n\nexport function consumePkceState(\n state: string,\n): { verifier: string; nonce: string } | null {\n const entry = pendingStates.get(state)\n pendingStates.delete(state)\n if (!entry || entry.expiresAt < Date.now()) return null\n return { verifier: entry.verifier, nonce: entry.nonce }\n}\n","import type { SamlConfig } from '@consenti/types'\n\nfunction escXml(s: string): string {\n return s.replace(/&/g, '&').replace(/\"/g, '"').replace(/</g, '<').replace(/>/g, '>')\n}\n\nexport function buildSamlMetadataXml(config: SamlConfig): string {\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<EntityDescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\"\n entityID=\"saml:sp:consenti\">\n <SPSSODescriptor\n protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\"\n AuthnRequestsSigned=\"false\"\n WantAssertionsSigned=\"true\">\n <NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat>\n <AssertionConsumerService\n Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\"\n Location=\"${escXml(config.callbackUrl)}\"\n index=\"0\"\n isDefault=\"true\"/>\n </SPSSODescriptor>\n</EntityDescriptor>`\n}\n\nexport interface SamlUserInfo {\n email: string\n roles: string[]\n}\n\n// Validates a SAML response using the `samlify` peer dependency.\n// Install: npm install samlify\nexport async function validateSamlResponse(\n samlResponse: string,\n config: SamlConfig,\n): Promise<SamlUserInfo | null> {\n let samlify: {\n ServiceProvider: (cfg: Record<string, unknown>) => {\n parseLoginResponse: (\n idp: unknown,\n type: string,\n req: { body: Record<string, string> },\n ) => Promise<{ extract: { nameID: string; attributes: Record<string, unknown> } }>\n }\n IdentityProvider: (cfg: Record<string, unknown>) => unknown\n }\n\n try {\n // @ts-expect-error -- samlify is an optional peer dependency; callers must install it\n samlify = (await import('samlify')) as unknown as typeof samlify\n } catch {\n console.warn('[Consenti] samlify is not installed. Install it to use SAML auth mode.')\n return null\n }\n\n try {\n const sp = samlify.ServiceProvider({\n entityID: 'saml:sp:consenti',\n assertionConsumerService: [\n {\n Binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',\n Location: config.callbackUrl,\n },\n ],\n })\n const idp = samlify.IdentityProvider({\n entityID: config.issuer,\n singleSignOnService: [\n {\n Binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',\n Location: config.entryPoint,\n },\n ],\n signingCert: config.cert,\n })\n const result = await sp.parseLoginResponse(idp, 'post', {\n body: { SAMLResponse: samlResponse },\n })\n const email = result.extract.nameID\n const rolesAttr = result.extract.attributes['roles']\n const roles = Array.isArray(rolesAttr)\n ? rolesAttr.filter((r): r is string => typeof r === 'string')\n : []\n return { email, roles }\n } catch (err) {\n console.warn('[Consenti] SAML response validation failed:', err)\n return null\n }\n}\n","import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto'\n\nconst BASE32_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'\n\nfunction base32Encode(buf: Buffer): string {\n let result = ''\n let bits = 0\n let value = 0\n for (const byte of buf) {\n value = (value << 8) | byte\n bits += 8\n while (bits >= 5) {\n result += BASE32_CHARS[(value >>> (bits - 5)) & 0x1f]\n bits -= 5\n }\n }\n if (bits > 0) result += BASE32_CHARS[(value << (5 - bits)) & 0x1f]\n return result\n}\n\nfunction base32Decode(str: string): Buffer {\n const clean = str.toUpperCase().replace(/[^A-Z2-7]/g, '')\n const bytes: number[] = []\n let bits = 0\n let value = 0\n for (const char of clean) {\n const idx = BASE32_CHARS.indexOf(char)\n if (idx < 0) continue\n value = (value << 5) | idx\n bits += 5\n if (bits >= 8) {\n bytes.push((value >>> (bits - 8)) & 0xff)\n bits -= 8\n }\n }\n return Buffer.from(bytes)\n}\n\nfunction hotp(secret: Buffer, counter: number): string {\n const buf = Buffer.alloc(8)\n let c = counter\n for (let i = 7; i >= 0; i--) {\n buf[i] = c & 0xff\n c = Math.floor(c / 256)\n }\n const hmac = createHmac('sha1', secret).update(buf).digest()\n const offset = hmac[hmac.length - 1]! & 0x0f\n const code =\n ((hmac[offset]! & 0x7f) << 24) |\n ((hmac[offset + 1]! & 0xff) << 16) |\n ((hmac[offset + 2]! & 0xff) << 8) |\n (hmac[offset + 3]! & 0xff)\n return String(code % 1_000_000).padStart(6, '0')\n}\n\nexport function generateTotpSecret(): string {\n return base32Encode(randomBytes(20))\n}\n\nexport function generateTotp(secret: string, time = Date.now()): string {\n return hotp(base32Decode(secret), Math.floor(time / 30_000))\n}\n\nconst usedTokens = new Map<string, number>() // token → expiresAt\n\nsetInterval(() => {\n const now = Date.now()\n for (const [token, expiresAt] of usedTokens) {\n if (now >= expiresAt) usedTokens.delete(token)\n }\n}, 90_000).unref()\n\nexport function verifyTotp(secret: string, token: string, window = 1): boolean {\n if (usedTokens.has(token)) return false\n const counter = Math.floor(Date.now() / 30_000)\n const secretBuf = base32Decode(secret)\n const tokenBuf = Buffer.from(token)\n for (let i = -window; i <= window; i++) {\n const expected = Buffer.from(hotp(secretBuf, counter + i))\n if (expected.length === tokenBuf.length && timingSafeEqual(expected, tokenBuf)) {\n usedTokens.set(token, Date.now() + 90_000)\n return true\n }\n }\n return false\n}\n\nexport function totpQrUrl(secret: string, email: string, issuer = 'Consenti'): string {\n const label = encodeURIComponent(`${issuer}:${email}`)\n const params = new URLSearchParams({\n secret,\n issuer,\n algorithm: 'SHA1',\n digits: '6',\n period: '30',\n })\n return `otpauth://totp/${label}?${params.toString()}`\n}\n","import type { CreateProfileInput, UpdateProfileInput, ProfileConfig } from '@consenti/types'\n\nexport interface ValidationResult {\n valid: boolean\n error?: string\n}\n\nexport function validateCreateProfile(body: unknown): ValidationResult {\n if (!body || typeof body !== 'object') return { valid: false, error: 'Request body must be a JSON object' }\n const b = body as Record<string, unknown>\n if (typeof b['name'] !== 'string' || !b['name']) return { valid: false, error: 'name is required' }\n if (typeof b['defaultLocale'] !== 'string' || !b['defaultLocale']) return { valid: false, error: 'defaultLocale is required' }\n if (!b['profileJson'] || typeof b['profileJson'] !== 'object') return { valid: false, error: 'profileJson is required' }\n const pj = b['profileJson'] as Record<string, unknown>\n if (typeof pj['cookieTemplateId'] !== 'string' || !pj['cookieTemplateId']) {\n return { valid: false, error: 'profileJson.cookieTemplateId is required' }\n }\n if (typeof pj['uiTemplateId'] !== 'string' || !pj['uiTemplateId']) {\n return { valid: false, error: 'profileJson.uiTemplateId is required' }\n }\n return { valid: true }\n}\n\nexport function validateUpdateProfile(body: unknown): ValidationResult {\n if (!body || typeof body !== 'object') return { valid: false, error: 'Request body must be a JSON object' }\n return { valid: true }\n}\n\nexport function castCreateProfile(body: Record<string, unknown>, tenantId: string): CreateProfileInput {\n return {\n tenantId,\n name: body['name'] as string,\n defaultLocale: body['defaultLocale'] as string,\n profileJson: body['profileJson'] as CreateProfileInput['profileJson'],\n }\n}\n\nexport function castUpdateProfile(body: Record<string, unknown>): UpdateProfileInput {\n const result: UpdateProfileInput = {}\n if (typeof body['name'] === 'string') result.name = body['name']\n if (typeof body['defaultLocale'] === 'string') result.defaultLocale = body['defaultLocale']\n if (body['profileJson'] != null) result.profileJson = body['profileJson'] as ProfileConfig\n return result\n}\n","import type { StorageAdapter, AuthConfig } from '@consenti/types'\nimport { json, parseJsonBody } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\nimport { validateCreateProfile, validateUpdateProfile, castCreateProfile, castUpdateProfile } from '../../validators/profile.validator'\nimport type { ProfileService } from '../../services/profile.service'\n\nexport function buildAdminProfileRoutes(\n service: ProfileService,\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request, perm?: string) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { user, denied: authError(user, perm) }\n }\n\n return {\n 'GET /profiles': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:view')\n if (denied) return denied\n return json(200, await service.list())\n }),\n\n 'GET /profiles/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:view')\n if (denied) return denied\n const profile = await service.get(p['id'] ?? '')\n if (!profile) return errorResponse(404, 'Profile not found')\n return json(200, profile)\n }),\n\n 'POST /profiles': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:create')\n if (denied) return denied\n const body = await parseJsonBody(req)\n const validation = validateCreateProfile(body)\n if (!validation.valid) return errorResponse(400, validation.error ?? 'Invalid body')\n const profile = await service.create(castCreateProfile(body as Record<string, unknown>, 'default'))\n return json(201, profile)\n }),\n\n 'PUT /profiles/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:update')\n if (denied) return denied\n const id = p['id'] ?? ''\n const body = await parseJsonBody(req)\n const validation = validateUpdateProfile(body)\n if (!validation.valid) return errorResponse(400, validation.error ?? 'Invalid body')\n const profile = await service.update(id, castUpdateProfile(body as Record<string, unknown>))\n return json(200, profile)\n }),\n\n 'DELETE /profiles/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:delete')\n if (denied) return denied\n await service.delete(p['id'] ?? '')\n return json(200, { success: true })\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig, ConsentFilters } from '@consenti/types'\nimport { json, getQueryParam, getQueryInt } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\n\nexport function buildAdminConsentRoutes(\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request, perm?: string) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { denied: authError(user, perm) }\n }\n\n return {\n 'GET /consents': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'consent:view')\n if (denied) return denied\n const url = new URL(req.url)\n const profileId = getQueryParam(url, 'profileId')\n const from = getQueryParam(url, 'from')\n const to = getQueryParam(url, 'to')\n const limit = getQueryInt(url, 'limit', 50)\n if (limit > 500) return errorResponse(400, 'limit must not exceed 500')\n const filters: ConsentFilters = {\n tenantId: 'default',\n page: getQueryInt(url, 'page', 1),\n limit,\n ...(profileId !== undefined ? { profileId } : {}),\n ...(from !== undefined ? { from } : {}),\n ...(to !== undefined ? { to } : {}),\n }\n const records = await storage.getConsents(filters)\n return json(200, records)\n }),\n\n 'GET /consents/:visitorId': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'consent:view')\n if (denied) return denied\n const record = await storage.getConsent(p['visitorId'] ?? '')\n if (!record) return errorResponse(404, 'Consent not found')\n return json(200, record)\n }),\n\n 'GET /consents/:visitorId/history': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'consent:view')\n if (denied) return denied\n const history = await storage.getConsentHistory(p['visitorId'] ?? '')\n return json(200, history)\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig, VisitorFilters } from '@consenti/types'\nimport { json, getQueryInt, getQueryParam } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\n\nexport function buildAdminVisitorRoutes(\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request, perm?: string) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { denied: authError(user, perm) }\n }\n\n return {\n 'GET /visitors': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'visitor:view')\n if (denied) return denied\n const url = new URL(req.url)\n const from = getQueryParam(url, 'from')\n const to = getQueryParam(url, 'to')\n const limit = getQueryInt(url, 'limit', 50)\n if (limit > 500) return errorResponse(400, 'limit must not exceed 500')\n const filters: VisitorFilters = {\n tenantId: 'default',\n page: getQueryInt(url, 'page', 1),\n limit,\n ...(from !== undefined ? { from } : {}),\n ...(to !== undefined ? { to } : {}),\n }\n const visitors = await storage.getVisitors(filters)\n return json(200, visitors)\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig } from '@consenti/types'\nimport { json, parseJsonBody } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\nimport type { UserService } from '../../services/user.service'\n\nexport function buildAdminUserRoutes(\n userService: UserService,\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request, perm?: string) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { user, denied: authError(user, perm) }\n }\n\n return {\n 'GET /users': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'user:view')\n if (denied) return denied\n const users = await userService.list()\n return json(200, users)\n }),\n\n 'GET /users/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'user:view')\n if (denied) return denied\n const user = await userService.get(p['id'] ?? '')\n if (!user) return errorResponse(404, 'User not found')\n const roles = await userService.getRoles(user.id)\n return json(200, { ...user, roles: roles.map(r => ({ id: r.id, name: r.name })) })\n }),\n\n 'POST /users': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user: actor, denied } = await auth(req, 'user:create')\n if (denied) return denied\n const body = await parseJsonBody(req)\n if (!body || typeof body !== 'object') return errorResponse(400, 'Invalid body')\n const b = body as Record<string, unknown>\n if (typeof b['name'] !== 'string' || !b['name']) return errorResponse(400, 'name is required')\n if (typeof b['email'] !== 'string' || !b['email']) return errorResponse(400, 'email is required')\n if (typeof b['password'] !== 'string' || !b['password']) return errorResponse(400, 'password is required')\n if (b['password'].length < 12) return errorResponse(400, 'password must be at least 12 characters')\n const created = await userService.create(\n {\n name: b['name'],\n email: b['email'],\n password: b['password'],\n ...(typeof b['roleId'] === 'string' ? { roleId: b['roleId'] } : {}),\n },\n actor!.sub,\n )\n return json(201, created)\n }),\n\n 'PUT /users/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user: actor, denied } = await auth(req, 'user:update')\n if (denied) return denied\n const id = p['id'] ?? ''\n const body = await parseJsonBody(req)\n if (!body || typeof body !== 'object') return errorResponse(400, 'Invalid body')\n const b = body as Record<string, unknown>\n if (typeof b['password'] === 'string' && b['password'].length < 12) {\n return errorResponse(400, 'password must be at least 12 characters')\n }\n const updated = await userService.update(\n id,\n {\n ...(typeof b['name'] === 'string' ? { name: b['name'] } : {}),\n ...(typeof b['email'] === 'string' ? { email: b['email'] } : {}),\n ...(b['isActive'] != null ? { isActive: Boolean(b['isActive']) } : {}),\n ...(typeof b['password'] === 'string' ? { password: b['password'] } : {}),\n },\n actor!.sub,\n )\n return json(200, updated)\n }),\n\n 'DELETE /users/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user: actor, denied } = await auth(req, 'user:delete')\n if (denied) return denied\n const id = p['id'] ?? ''\n if (id === actor!.sub) return errorResponse(400, 'Cannot delete your own account')\n await userService.delete(id, actor!.sub)\n return json(200, { success: true })\n }),\n\n 'POST /users/:id/roles': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user: actor, denied } = await auth(req, 'role:update')\n if (denied) return denied\n const body = await parseJsonBody(req)\n if (!body || typeof body !== 'object') return errorResponse(400, 'Invalid body')\n const b = body as Record<string, unknown>\n if (typeof b['roleId'] !== 'string') return errorResponse(400, 'roleId is required')\n const tenantId = typeof b['tenantId'] === 'string' ? b['tenantId'] : undefined\n await userService.assignRole(p['id'] ?? '', b['roleId'], tenantId)\n await storage.createLog({\n tenantId: 'default',\n userId: actor!.sub,\n action: 'user.role_assigned',\n resourceType: 'user',\n ...(p['id'] != null ? { resourceId: p['id'] } : {}),\n newData: { roleId: b['roleId'] },\n })\n return json(200, { success: true })\n }),\n\n 'DELETE /users/:id/roles/:roleId': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user: actor, denied } = await auth(req, 'role:update')\n if (denied) return denied\n const url = new URL(req.url)\n const revokedTenantId = url.searchParams.get('tenantId') ?? undefined\n await userService.revokeRole(p['id'] ?? '', p['roleId'] ?? '', revokedTenantId)\n await storage.createLog({\n tenantId: 'default',\n userId: actor!.sub,\n action: 'user.role_revoked',\n resourceType: 'user',\n ...(p['id'] != null ? { resourceId: p['id'] } : {}),\n oldData: { roleId: p['roleId'] },\n })\n return json(200, { success: true })\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig } from '@consenti/types'\nimport { json, parseJsonBody } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\n\nexport function buildAdminRoleRoutes(\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request, perm?: string) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { user, denied: authError(user, perm) }\n }\n\n return {\n 'GET /roles': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'role:view')\n if (denied) return denied\n const roles = await storage.getRoles('default')\n return json(200, roles)\n }),\n\n 'GET /roles/:id/permissions': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'role:view')\n if (denied) return denied\n const perms = await storage.getPermissionsForRole(p['id'] ?? '')\n return json(200, perms)\n }),\n\n 'POST /roles': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user: actor, denied } = await auth(req, 'role:create')\n if (denied) return denied\n const body = await parseJsonBody(req)\n if (!body || typeof body !== 'object') return errorResponse(400, 'Invalid body')\n const b = body as Record<string, unknown>\n if (typeof b['name'] !== 'string' || !b['name']) return errorResponse(400, 'name is required')\n const role = await storage.createRole({\n tenantId: 'default',\n name: b['name'],\n ...(typeof b['description'] === 'string' ? { description: b['description'] } : {}),\n })\n await storage.createLog({\n tenantId: 'default',\n userId: actor!.sub,\n action: 'role.created',\n resourceType: 'role',\n resourceId: role.id,\n newData: role,\n })\n return json(201, role)\n }),\n\n 'PUT /roles/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user: actor, denied } = await auth(req, 'role:update')\n if (denied) return denied\n const body = await parseJsonBody(req)\n if (!body || typeof body !== 'object') return errorResponse(400, 'Invalid body')\n const b = body as Record<string, unknown>\n const role = await storage.updateRole(p['id'] ?? '', {\n ...(typeof b['name'] === 'string' ? { name: b['name'] } : {}),\n ...(typeof b['description'] === 'string' ? { description: b['description'] } : {}),\n })\n await storage.createLog({\n tenantId: 'default',\n userId: actor!.sub,\n action: 'role.updated',\n resourceType: 'role',\n resourceId: role.id,\n newData: role,\n })\n return json(200, role)\n }),\n\n 'DELETE /roles/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user: actor, denied } = await auth(req, 'role:delete')\n if (denied) return denied\n await storage.deleteRole(p['id'] ?? '')\n await storage.createLog({\n tenantId: 'default',\n userId: actor!.sub,\n action: 'role.deleted',\n resourceType: 'role',\n ...(p['id'] != null ? { resourceId: p['id'] } : {}),\n })\n return json(200, { success: true })\n }),\n\n 'GET /permissions': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'role:view')\n if (denied) return denied\n const perms = await storage.getAllPermissions()\n return json(200, perms)\n }),\n\n 'POST /roles/:id/permissions': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'role:update')\n if (denied) return denied\n const body = await parseJsonBody(req)\n if (!body || typeof body !== 'object') return errorResponse(400, 'Invalid body')\n const b = body as Record<string, unknown>\n if (typeof b['permissionId'] !== 'string') return errorResponse(400, 'permissionId is required')\n await storage.assignPermissionToRole(p['id'] ?? '', b['permissionId'])\n return json(200, { success: true })\n }),\n\n 'DELETE /roles/:id/permissions/:permissionId': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'role:update')\n if (denied) return denied\n await storage.revokePermissionFromRole(p['id'] ?? '', p['permissionId'] ?? '')\n return json(200, { success: true })\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig, AuditFilters } from '@consenti/types'\nimport { json, getQueryParam, getQueryInt } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\n\nexport function buildAdminAuditRoutes(\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request, perm?: string) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { denied: authError(user, perm) }\n }\n\n return {\n 'GET /audit': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'audit:view')\n if (denied) return denied\n const url = new URL(req.url)\n const action = getQueryParam(url, 'action')\n const resourceType = getQueryParam(url, 'resourceType')\n const from = getQueryParam(url, 'from')\n const to = getQueryParam(url, 'to')\n const limit = getQueryInt(url, 'limit', 50)\n if (limit > 500) return errorResponse(400, 'limit must not exceed 500')\n const filters: AuditFilters = {\n tenantId: 'default',\n page: getQueryInt(url, 'page', 1),\n limit,\n ...(action !== undefined ? { action } : {}),\n ...(resourceType !== undefined ? { resourceType } : {}),\n ...(from !== undefined ? { from } : {}),\n ...(to !== undefined ? { to } : {}),\n }\n const logs = await storage.getLogs(filters)\n return json(200, logs)\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig } from '@consenti/types'\nimport { json, getQueryInt } from '../../utils/http'\nimport { withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\n\nexport function buildAdminStatsRoutes(\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { denied: authError(user, 'consent:view') }\n }\n\n return {\n 'GET /stats/overview': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const stats = await storage.getOverviewStats('default')\n return json(200, stats)\n }),\n\n 'GET /stats/categories': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const stats = await storage.getCategoryStats('default')\n return json(200, stats)\n }),\n\n 'GET /stats/timeline': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const url = new URL(req.url)\n const days = getQueryInt(url, 'days', 30)\n const timeline = await storage.getTimeline('default', days)\n return json(200, timeline)\n }),\n\n 'GET /stats/countries': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const countries = await storage.getCountries('default')\n return json(200, countries)\n }),\n\n 'GET /stats/gpc': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const gpc = await storage.getGpcStats('default')\n return json(200, gpc)\n }),\n\n 'GET /stats/aggregate': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const tenants = await storage.getTenants()\n const rows = await Promise.all(\n tenants.map(async t => {\n const s = await storage.getOverviewStats(t.id)\n return { tenantId: t.id, tenantName: t.name, ...s }\n }),\n )\n const aggregate = rows.reduce(\n (acc, r) => ({\n totalConsents: acc.totalConsents + r.totalConsents,\n totalVisitors: acc.totalVisitors + r.totalVisitors,\n gpcDetectedCount: acc.gpcDetectedCount + r.gpcDetectedCount,\n }),\n { totalConsents: 0, totalVisitors: 0, gpcDetectedCount: 0 },\n )\n return json(200, { aggregate, perTenant: rows })\n }),\n }\n}\n","import type {\n StorageAdapter, AuthConfig, ConsentFilters, AuditFilters,\n ConsentDbRecord, AuditLog,\n} from '@consenti/types'\nimport { withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\nimport { getQueryParam } from '../../utils/http'\n\nfunction escapeCsv(val: string | number | boolean | null | undefined): string {\n const s = val == null ? '' : String(val)\n if (s.includes(',') || s.includes('\"') || s.includes('\\n')) {\n return `\"${s.replace(/\"/g, '\"\"')}\"`\n }\n return s\n}\n\nfunction consentToCsvRow(r: ConsentDbRecord): string {\n return [\n r.id, r.visitorId, r.profileId, r.profileVersion, r.locale,\n JSON.stringify(r.consentJson), r.gpcDetected ? '1' : '0',\n r.source, r.createdAt, r.updatedAt,\n ].map(escapeCsv).join(',') + '\\n'\n}\n\nfunction auditToCsvRow(r: AuditLog): string {\n return [\n r.id, r.userId ?? '', r.action, r.resourceType, r.resourceId ?? '', r.createdAt,\n ].map(escapeCsv).join(',') + '\\n'\n}\n\nexport function buildAdminExportRoutes(\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { denied: authError(user, 'export:run') }\n }\n\n return {\n 'GET /export/consents': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const url = new URL(req.url)\n const format = getQueryParam(url, 'format') ?? 'csv'\n const profileId = getQueryParam(url, 'profileId')\n const from = getQueryParam(url, 'from')\n const to = getQueryParam(url, 'to')\n const filters: ConsentFilters = {\n tenantId: 'default',\n ...(profileId !== undefined ? { profileId } : {}),\n ...(from !== undefined ? { from } : {}),\n ...(to !== undefined ? { to } : {}),\n }\n\n if (format === 'json') {\n const records: ConsentDbRecord[] = []\n for await (const r of storage.streamConsents(filters)) records.push(r)\n return new Response(JSON.stringify(records), {\n status: 200,\n headers: {\n 'Content-Type': 'application/json',\n 'Content-Disposition': 'attachment; filename=\"consents.json\"',\n },\n })\n }\n\n const enc = new TextEncoder()\n const header = 'id,visitor_id,profile_id,profile_version,locale,consent_json,gpc_detected,source,created_at,updated_at\\n'\n const stream = new ReadableStream({\n async start(controller) {\n controller.enqueue(enc.encode(header))\n for await (const r of storage.streamConsents(filters)) {\n controller.enqueue(enc.encode(consentToCsvRow(r)))\n }\n controller.close()\n },\n })\n return new Response(stream, {\n status: 200,\n headers: {\n 'Content-Type': 'text/csv; charset=utf-8',\n 'Content-Disposition': 'attachment; filename=\"consents.csv\"',\n },\n })\n }),\n\n 'GET /export/consents/xlsx': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n\n interface XlsxModule {\n utils: {\n book_new(): object\n json_to_sheet(rows: object[]): object\n book_append_sheet(wb: object, ws: object, name: string): void\n }\n write(wb: object, opts: { type: string; bookType: string }): Uint8Array\n }\n let XlsxMod: XlsxModule | null = null\n try {\n // @ts-expect-error -- xlsx is an optional peer dependency; install it to use XLSX export\n XlsxMod = (await import('xlsx')) as XlsxModule\n } catch {\n return new Response(JSON.stringify({ error: 'xlsx peer dependency not installed. Run: npm install xlsx' }), {\n status: 501,\n headers: { 'Content-Type': 'application/json' },\n })\n }\n if (!XlsxMod) return new Response(null, { status: 501 })\n\n const url = new URL(req.url)\n const profileId = url.searchParams.get('profileId') ?? undefined\n const from = url.searchParams.get('from') ?? undefined\n const to = url.searchParams.get('to') ?? undefined\n const filters: ConsentFilters = {\n tenantId: 'default',\n ...(profileId !== undefined ? { profileId } : {}),\n ...(from !== undefined ? { from } : {}),\n ...(to !== undefined ? { to } : {}),\n }\n\n const rows: Record<string, unknown>[] = []\n for await (const r of storage.streamConsents(filters)) {\n rows.push({\n id: r.id,\n visitor_id: r.visitorId,\n profile_id: r.profileId,\n profile_version: r.profileVersion,\n locale: r.locale,\n consent_json: JSON.stringify(r.consentJson),\n gpc_detected: r.gpcDetected ? 1 : 0,\n age_verified: r.ageVerified ? 1 : 0,\n tcf_string: r.tcfString ?? '',\n source: r.source,\n created_at: r.createdAt,\n updated_at: r.updatedAt,\n })\n }\n\n const wb = XlsxMod.utils.book_new()\n const ws = XlsxMod.utils.json_to_sheet(rows)\n XlsxMod.utils.book_append_sheet(wb, ws, 'Consents')\n const buf = XlsxMod.write(wb, { type: 'buffer', bookType: 'xlsx' })\n return new Response(buf as unknown as BodyInit, {\n status: 200,\n headers: {\n 'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n 'Content-Disposition': 'attachment; filename=\"consents.xlsx\"',\n },\n })\n }),\n\n 'GET /export/audit': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const url = new URL(req.url)\n const format = getQueryParam(url, 'format') ?? 'csv'\n const from = getQueryParam(url, 'from')\n const to = getQueryParam(url, 'to')\n const filters: AuditFilters = {\n tenantId: 'default',\n ...(from !== undefined ? { from } : {}),\n ...(to !== undefined ? { to } : {}),\n }\n\n if (format === 'json') {\n const logs: AuditLog[] = []\n for await (const r of storage.streamAuditLogs(filters)) logs.push(r)\n return new Response(JSON.stringify(logs), {\n status: 200,\n headers: {\n 'Content-Type': 'application/json',\n 'Content-Disposition': 'attachment; filename=\"audit.json\"',\n },\n })\n }\n\n const enc = new TextEncoder()\n const header = 'id,user_id,action,resource_type,resource_id,created_at\\n'\n const stream = new ReadableStream({\n async start(controller) {\n controller.enqueue(enc.encode(header))\n for await (const r of storage.streamAuditLogs(filters)) {\n controller.enqueue(enc.encode(auditToCsvRow(r)))\n }\n controller.close()\n },\n })\n return new Response(stream, {\n status: 200,\n headers: {\n 'Content-Type': 'text/csv; charset=utf-8',\n 'Content-Disposition': 'attachment; filename=\"audit.csv\"',\n },\n })\n }),\n }\n}\n","import { randomBytes, createHash } from 'node:crypto'\nimport type { StorageAdapter, AuthConfig } from '@consenti/types'\nimport { json } from '../../utils/http'\nimport { withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\n\nfunction generateApiKey(): { raw: string; hash: string } {\n const raw = `ck_live_${randomBytes(24).toString('hex')}`\n const hash = createHash('sha256').update(raw).digest('hex')\n return { raw, hash }\n}\n\nexport function buildAdminApiKeyRoutes(\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { user, denied: authError(user, 'settings:update') }\n }\n\n return {\n 'GET /apikeys': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const keys = await storage.getApiKeys('default')\n return json(200, keys.map(k => ({ id: k.id, name: k.name, isActive: k.isActive, createdAt: k.createdAt })))\n }),\n\n 'POST /apikeys': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const body = await req.json() as { name?: string; tenantId?: string }\n if (!body.name) return json(400, { error: 'name is required' })\n const { raw, hash } = generateApiKey()\n const created = await storage.createApiKey({ tenantId: body.tenantId ?? 'default', name: body.name, keyHash: hash })\n return json(201, { id: created.id, name: created.name, key: raw, createdAt: created.createdAt })\n }),\n\n 'DELETE /apikeys/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n await storage.revokeApiKey(p['id'] ?? '')\n return json(204, null)\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig } from '@consenti/types'\nimport { json, parseJsonBody } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\n\nexport function buildAdminTenantRoutes(\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request, perm: string) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { user, denied: authError(user, perm) }\n }\n\n return {\n 'GET /tenants': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'settings:update')\n if (denied) return denied\n const tenants = await storage.getTenants()\n return json(200, tenants)\n }),\n\n 'POST /tenants': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'settings:update')\n if (denied) return denied\n const body = await parseJsonBody(req)\n if (!body || typeof body !== 'object') return errorResponse(400, 'Invalid body')\n const b = body as Record<string, unknown>\n if (typeof b['name'] !== 'string' || typeof b['slug'] !== 'string') {\n return errorResponse(400, 'name and slug are required')\n }\n const tenant = await storage.createTenant({ name: b['name'], slug: b['slug'] })\n return json(201, tenant)\n }),\n\n 'PUT /tenants/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'settings:update')\n if (denied) return denied\n const body = await parseJsonBody(req)\n if (!body || typeof body !== 'object') return errorResponse(400, 'Invalid body')\n const b = body as Record<string, unknown>\n const tenant = await storage.updateTenant(p['id'] ?? '', {\n ...(typeof b['name'] === 'string' ? { name: b['name'] } : {}),\n ...(typeof b['slug'] === 'string' ? { slug: b['slug'] } : {}),\n })\n return json(200, tenant)\n }),\n\n 'DELETE /tenants/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'settings:update')\n if (denied) return denied\n const id = p['id'] ?? ''\n if (id === 'default') return errorResponse(400, 'Cannot delete the default tenant')\n await storage.deleteTenant(id)\n return json(200, { success: true })\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig } from '@consenti/types'\nimport { getGvl } from '../../tcf/gvl-cache'\nimport { json } from '../../utils/http'\nimport { withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\n\nexport function buildAdminTcfRoutes(\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { denied: authError(user, 'consent:view') }\n }\n\n return {\n 'GET /tcf/vendors': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const gvl = await getGvl()\n if (!gvl) return json(503, { error: 'GVL not available. Enable tcf.enabled in config.' })\n const url = new URL(req.url)\n const search = url.searchParams.get('q')?.toLowerCase()\n const page = Math.max(1, parseInt(url.searchParams.get('page') ?? '1', 100))\n const limit = Math.min(200, Math.max(1, parseInt(url.searchParams.get('limit') ?? '100', 10)))\n const vendors = Object.values(gvl.vendors)\n const filtered = search\n ? vendors.filter(v => v.name.toLowerCase().includes(search))\n : vendors\n const total = filtered.length\n const totalPages = Math.max(1, Math.ceil(total / limit))\n const safePage = Math.min(page, totalPages)\n const start = (safePage - 1) * limit\n return json(200, {\n vendorListVersion: gvl.vendorListVersion,\n total,\n page: safePage,\n totalPages,\n vendors: filtered.slice(start, start + limit),\n })\n }),\n\n 'GET /tcf/purposes': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const gvl = await getGvl()\n if (!gvl) return json(503, { error: 'GVL not available. Enable tcf.enabled in config.' })\n return json(200, { purposes: Object.values(gvl.purposes) })\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig } from '@consenti/types'\nimport { json, parseJsonBody } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\n\nexport function buildAdminCookieTemplateRoutes(storage: StorageAdapter, authConfig: AuthConfig, secret: string, tenantId = 'default') {\n async function auth(req: Request, perm?: string) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { user, denied: authError(user, perm) }\n }\n\n return {\n 'GET /cookie-templates': async (req: Request): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:view')\n if (denied) return denied\n return json(200, await storage.getCookieTemplates(tenantId))\n }),\n\n 'GET /cookie-templates/:id': async (req: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:view')\n if (denied) return denied\n const t = await storage.getCookieTemplate(params['id']!)\n return t ? json(200, t) : errorResponse(404, 'Cookie template not found')\n }),\n\n 'POST /cookie-templates': async (req: Request): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:create')\n if (denied) return denied\n const body = await parseJsonBody<{ name?: unknown; cookies?: unknown }>(req)\n if (!body?.name || typeof body.name !== 'string') return errorResponse(400, 'name is required')\n if (!Array.isArray(body.cookies)) return errorResponse(400, 'cookies must be an array')\n const t = await storage.createCookieTemplate({ tenantId, name: body.name, cookies: body.cookies as never })\n return json(201, t)\n }),\n\n 'PUT /cookie-templates/:id': async (req: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:update')\n if (denied) return denied\n const body = await parseJsonBody<{ name?: unknown; cookies?: unknown }>(req)\n const update: { name?: string; cookies?: never } = {}\n if (body?.name !== undefined && typeof body.name === 'string') update.name = body.name\n if (body?.cookies !== undefined && Array.isArray(body.cookies)) update.cookies = body.cookies as never\n const t = await storage.updateCookieTemplate(params['id']!, update)\n return json(200, t)\n }),\n\n 'DELETE /cookie-templates/:id': async (req: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:delete')\n if (denied) return denied\n await storage.deleteCookieTemplate(params['id']!)\n return json(200, { ok: true })\n }),\n\n 'POST /cookie-templates/:id/copy': async (req: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:create')\n if (denied) return denied\n const body = await parseJsonBody<{ name?: unknown }>(req)\n const src = await storage.getCookieTemplate(params['id']!)\n if (!src) return errorResponse(404, 'Cookie template not found')\n const newName = (typeof body?.name === 'string' && body.name.trim()) ? body.name.trim() : `${src.name} (Copy)`\n const t = await storage.copyCookieTemplate(params['id']!, newName)\n return json(201, t)\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig } from '@consenti/types'\nimport { json, parseJsonBody } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\n\nexport function buildAdminUITemplateRoutes(storage: StorageAdapter, authConfig: AuthConfig, secret: string, tenantId = 'default') {\n async function auth(req: Request, perm?: string) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { user, denied: authError(user, perm) }\n }\n\n return {\n 'GET /ui-templates': async (req: Request): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:view')\n if (denied) return denied\n return json(200, await storage.getUITemplates(tenantId))\n }),\n\n 'GET /ui-templates/:id': async (req: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:view')\n if (denied) return denied\n const t = await storage.getUITemplate(params['id']!)\n return t ? json(200, t) : errorResponse(404, 'UI template not found')\n }),\n\n 'POST /ui-templates': async (req: Request): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:create')\n if (denied) return denied\n const body = await parseJsonBody<Record<string, unknown>>(req)\n if (!body?.name || typeof body.name !== 'string') return errorResponse(400, 'name is required')\n if (!body.mainBanner || !body.gpcBanner || !body.preferenceModal) return errorResponse(400, 'mainBanner, gpcBanner, and preferenceModal are required')\n const t = await storage.createUITemplate({\n tenantId,\n name: body.name,\n mainBanner: body.mainBanner as never,\n gpcBanner: body.gpcBanner as never,\n preferenceModal: body.preferenceModal as never,\n })\n return json(201, t)\n }),\n\n 'PUT /ui-templates/:id': async (req: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:update')\n if (denied) return denied\n const body = await parseJsonBody<Record<string, unknown>>(req)\n const update: Record<string, unknown> = {}\n if (typeof body?.name === 'string') update['name'] = body.name\n if (body?.mainBanner) update['mainBanner'] = body.mainBanner\n if (body?.gpcBanner) update['gpcBanner'] = body.gpcBanner\n if (body?.preferenceModal) update['preferenceModal'] = body.preferenceModal\n const t = await storage.updateUITemplate(params['id']!, update as never)\n return json(200, t)\n }),\n\n 'DELETE /ui-templates/:id': async (req: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:delete')\n if (denied) return denied\n await storage.deleteUITemplate(params['id']!)\n return json(200, { ok: true })\n }),\n\n 'POST /ui-templates/:id/copy': async (req: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:create')\n if (denied) return denied\n const body = await parseJsonBody<{ name?: unknown }>(req)\n const src = await storage.getUITemplate(params['id']!)\n if (!src) return errorResponse(404, 'UI template not found')\n const newName = (typeof body?.name === 'string' && body.name.trim()) ? body.name.trim() : `${src.name} (Copy)`\n const t = await storage.copyUITemplate(params['id']!, newName)\n return json(201, t)\n }),\n }\n}\n","import { createHash } from 'node:crypto'\nimport type { StorageAdapter } from '@consenti/types'\n\nexport async function resolveTenant(\n req: Request,\n storage: StorageAdapter,\n defaultTenantId: string,\n): Promise<string> {\n const auth = req.headers.get('authorization')\n if (!auth?.startsWith('Bearer ck_')) return defaultTenantId\n\n const rawKey = auth.slice(7)\n const keyHash = createHash('sha256').update(rawKey).digest('hex')\n const apiKey = await storage.getApiKeyByHash(keyHash)\n return apiKey?.tenantId ?? defaultTenantId\n}\n","interface RateLimitEntry {\n count: number\n resetAt: number\n}\n\nexport class RateLimiter {\n private store = new Map<string, RateLimitEntry>()\n\n constructor(\n private windowMs: number = 60_000,\n private maxRequests: number = 60,\n ) {\n setInterval(() => {\n const now = Date.now()\n for (const [key, entry] of this.store) {\n if (now >= entry.resetAt) this.store.delete(key)\n }\n }, this.windowMs).unref()\n }\n\n check(key: string): boolean {\n const now = Date.now()\n const entry = this.store.get(key)\n\n if (!entry || now >= entry.resetAt) {\n this.store.set(key, { count: 1, resetAt: now + this.windowMs })\n return true\n }\n\n entry.count += 1\n return entry.count <= this.maxRequests\n }\n\n // Returns false if either the IP bucket or the profileId bucket is exhausted.\n checkRequest(ip: string, profileId?: string): boolean {\n const ipOk = this.check(`ip:${ip}`)\n if (!ipOk) return false\n if (profileId) return this.check(`profile:${profileId}`)\n return true\n }\n}\n"],"mappings":"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","names":["import_promises","import_node_path","MAX_PAGE_SIZE","MAX_PAGE_SIZE","q","page","visitors","mapProfile","mapConsent","mapHistory","mapVisitor","mapUser","mapRole","mapPermission","mapAuditLog","page","visitors","mapProfile","mapConsent","mapHistory","mapVisitor","mapUser","mapRole","mapPermission","mapAuditLog","page","visitors","rows","row","import_node_crypto","MAX_PAGE_SIZE","randomProfileId","c","v","c","profiles","status","visitors","profiles","visitors","roles","permissions","profiles","visitors","profiles","import_node_crypto","roles","permissions","import_node_crypto","roles","import_node_crypto","base64url","roles","permissions","visitors","roles","roles","tenants","import_node_crypto","tenants","page","import_node_crypto","dashboardDir"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../../../node_modules/tsup/assets/cjs_shims.js","../src/core/plugin-engine.ts","../src/utils/handle-config.ts","../src/tcf/gvl-cache.ts","../src/openapi/spec.ts","../src/utils/crypto.ts","../src/utils/storage-path.ts","../src/storage/seed-data.ts","../src/storage/sqlite/better-sqlite3.adapter.ts","../src/storage/sqlite/node-sqlite3-wasm.adapter.ts","../src/storage/sqlite/node-sqlite-builtin.adapter.ts","../src/storage/mongodb/mongodb.adapter.ts","../src/storage/mysql/mysql.adapter.ts","../src/storage/postgresql/postgresql.adapter.ts","../src/storage/json/json-file.adapter.ts","../src/repositories/profile.repo.ts","../src/repositories/consent.repo.ts","../src/repositories/visitor.repo.ts","../src/repositories/audit.repo.ts","../src/repositories/user.repo.ts","../src/core/profile-engine.ts","../src/services/profile.service.ts","../src/workers/profile-json-worker-launcher.ts","../src/workers/profile-json-worker-core.ts","../src/storage/s3/s3-client.ts","../src/data/timezone-country.ts","../src/services/geo-resolver.service.ts","../src/services/locale-json-cache.service.ts","../src/utils/safe-json-write.ts","../src/core/consent-engine.ts","../src/tcf/tc-string.ts","../src/services/consent.service.ts","../src/services/visitor.service.ts","../src/services/user.service.ts","../src/auth/local.auth.ts","../src/utils/http.ts","../src/middleware/error.middleware.ts","../src/routes/public/profile.routes.ts","../src/utils/cookie.ts","../src/middleware/cors.middleware.ts","../src/validators/consent.validator.ts","../src/routes/public/consent.routes.ts","../src/routes/admin/auth.routes.ts","../src/middleware/auth.middleware.ts","../src/auth/oidc.auth.ts","../src/auth/saml.auth.ts","../src/auth/totp.ts","../../../packages/utils/src/compliance.ts","../src/validators/profile.validator.ts","../src/services/compliance-validator.service.ts","../src/routes/admin/profiles.routes.ts","../src/routes/admin/consents.routes.ts","../src/routes/admin/visitors.routes.ts","../src/routes/admin/users.routes.ts","../src/routes/admin/roles.routes.ts","../src/routes/admin/audit.routes.ts","../src/routes/admin/stats.routes.ts","../src/routes/admin/export.routes.ts","../src/routes/admin/apikeys.routes.ts","../src/routes/admin/tenants.routes.ts","../src/routes/admin/tcf.routes.ts","../src/routes/admin/cookie-templates.routes.ts","../src/routes/admin/ui-templates.routes.ts","../src/routes/admin/analytics.routes.ts","../src/middleware/tenant.middleware.ts","../src/middleware/rate-limit.middleware.ts"],"sourcesContent":["import { EventEmitter } from 'node:events'\nimport { readFile } from 'node:fs/promises'\nimport { join, extname, dirname } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { PluginEngine } from './core/plugin-engine'\nimport { buildConsentiRuntimeConfig, buildConsentiConfigScript, injectConfigScript } from './utils/handle-config'\nimport { startGvlRefresh, stopGvlRefresh } from './tcf/gvl-cache'\nimport { OPENAPI_PUBLIC_SPEC, OPENAPI_ADMIN_SPEC } from './openapi/spec'\nimport { BetterSqlite3Adapter } from './storage/sqlite/better-sqlite3.adapter'\nimport { NodeSqlite3WasmAdapter } from './storage/sqlite/node-sqlite3-wasm.adapter'\nimport { NodeSqliteBuiltinAdapter } from './storage/sqlite/node-sqlite-builtin.adapter'\nimport { MongoDBAdapter } from './storage/mongodb/mongodb.adapter'\nimport { MySQLAdapter } from './storage/mysql/mysql.adapter'\nimport { PostgreSQLAdapter } from './storage/postgresql/postgresql.adapter'\nimport { JsonFileAdapter } from './storage/json/json-file.adapter'\nimport { ProfileRepo } from './repositories/profile.repo'\nimport { ConsentRepo } from './repositories/consent.repo'\nimport { VisitorRepo } from './repositories/visitor.repo'\nimport { AuditRepo } from './repositories/audit.repo'\nimport { UserRepo } from './repositories/user.repo'\nimport { ProfileService } from './services/profile.service'\nimport { GeoResolverService } from './services/geo-resolver.service'\nimport { LocaleJsonCacheService } from './services/locale-json-cache.service'\nimport { ConsentService } from './services/consent.service'\nimport { VisitorService } from './services/visitor.service'\nimport { UserService } from './services/user.service'\nimport { LocalAuth } from './auth/local.auth'\nimport { buildProfileRoutes } from './routes/public/profile.routes'\nimport { buildConsentRoutes } from './routes/public/consent.routes'\nimport { buildAdminAuthRoutes } from './routes/admin/auth.routes'\nimport { buildAdminProfileRoutes } from './routes/admin/profiles.routes'\nimport { buildAdminConsentRoutes } from './routes/admin/consents.routes'\nimport { buildAdminVisitorRoutes } from './routes/admin/visitors.routes'\nimport { buildAdminUserRoutes } from './routes/admin/users.routes'\nimport { buildAdminRoleRoutes } from './routes/admin/roles.routes'\nimport { buildAdminAuditRoutes } from './routes/admin/audit.routes'\nimport { buildAdminStatsRoutes } from './routes/admin/stats.routes'\nimport { buildAdminExportRoutes } from './routes/admin/export.routes'\nimport { buildAdminApiKeyRoutes } from './routes/admin/apikeys.routes'\nimport { buildAdminTenantRoutes } from './routes/admin/tenants.routes'\nimport { buildAdminTcfRoutes } from './routes/admin/tcf.routes'\nimport { buildAdminCookieTemplateRoutes } from './routes/admin/cookie-templates.routes'\nimport { buildAdminUITemplateRoutes } from './routes/admin/ui-templates.routes'\nimport { buildAdminAnalyticsRoutes } from './routes/admin/analytics.routes'\nimport { resolveStoragePaths } from './utils/storage-path'\nimport { resolveTenant } from './middleware/tenant.middleware'\nimport { RateLimiter } from './middleware/rate-limit.middleware'\nimport { handleCors, withCors, addSecurityHeaders } from './middleware/cors.middleware'\nimport { errorResponse } from './middleware/error.middleware'\nimport { nodeRequestToFetch, fetchResponseToNode, PayloadTooLargeError } from './utils/http'\nimport type { ConsentiServerConfig, StorageAdapter, StorageConfig } from '@consenti/types'\nimport { EMBEDDED_COMPLIANCE_MAP } from '@consenti/utils'\nimport type { IncomingMessage, ServerResponse } from 'node:http'\n\n// ── Path resolution ────────────────────────────────────────────────────────────\n\nconst DIST_DIR = dirname(fileURLToPath(import.meta.url))\n// new URL pattern is recognised by @vercel/nft (Next.js standalone tracer),\n// causing it to include the dashboard/ directory for any consumer's standalone build.\nexport const dashboardDir: string = fileURLToPath(new URL('./dashboard', import.meta.url))\n\nconst MIME: Record<string, string> = {\n '.html': 'text/html; charset=utf-8',\n '.js': 'application/javascript; charset=utf-8',\n '.mjs': 'application/javascript; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.json': 'application/json',\n '.png': 'image/png',\n '.svg': 'image/svg+xml',\n '.ico': 'image/x-icon',\n '.woff2': 'font/woff2',\n '.woff': 'font/woff',\n '.ttf': 'font/ttf',\n}\n\nasync function tryServeDashboard(\n pathname: string,\n basePath: string,\n dashboardDir: string,\n res: ServerResponse,\n configScript: string,\n): Promise<boolean> {\n const rel = pathname.slice(basePath.length) || '/'\n if (rel.startsWith('/api/') || rel.startsWith('/admin/')) return false\n const target = rel === '/' || rel === '' || !extname(rel)\n ? join(dashboardDir, 'index.html')\n : join(dashboardDir, rel)\n // directory traversal guard\n if (!target.startsWith(dashboardDir)) return false\n try {\n const raw = await readFile(target)\n const ext = extname(target).toLowerCase()\n const isHtml = ext === '.html' || ext === ''\n const ct = MIME[ext] ?? 'application/octet-stream'\n res.writeHead(200, { 'Content-Type': ct })\n res.end(isHtml ? injectConfigScript(raw, configScript) : raw)\n return true\n } catch {\n return false\n }\n}\n\nasync function serveDistFile(filePath: string, contentType: string): Promise<Response> {\n try {\n const data = await readFile(filePath)\n return new Response(data, { headers: { 'Content-Type': contentType, 'Cache-Control': 'public, max-age=3600' } })\n } catch {\n return new Response('Not Found', { status: 404 })\n }\n}\n\n// ── Minimal path router ────────────────────────────────────────────────────────\n\ntype Handler = (req: Request, params: Record<string, string>) => Promise<Response>\n\ninterface RouteEntry {\n method: string\n pattern: RegExp\n paramNames: string[]\n handler: Handler\n rateLimit: boolean\n}\n\nfunction compilePath(path: string): { pattern: RegExp; paramNames: string[] } {\n const paramNames: string[] = []\n const regexParts = path.split('/').map(part => {\n if (part.startsWith(':')) {\n paramNames.push(part.slice(1))\n return '([^/]+)'\n }\n return part.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n })\n return { pattern: new RegExp(`^${regexParts.join('\\\\/')}$`), paramNames }\n}\n\ninterface RouteGroup {\n prefix: string\n routes: Record<string, Handler>\n rateLimit?: boolean\n}\n\nfunction branded404(basePath: string): Response {\n const docsHref = `${basePath}/api/docs`\n const html = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<title>404 — Consenti</title>\n<style>\n *{box-sizing:border-box;margin:0;padding:0}\n body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:#0f1117;color:#e2e8f0;min-height:100vh;display:flex;align-items:center;justify-content:center;padding:2rem}\n .card{text-align:center;max-width:480px;width:100%}\n .badge{display:inline-flex;align-items:center;gap:.5rem;background:#1e2330;border:1px solid #2d3347;border-radius:999px;padding:.35rem .85rem;font-size:.75rem;letter-spacing:.08em;text-transform:uppercase;color:#7c8db5;margin-bottom:2rem}\n .badge svg{width:14px;height:14px;fill:#4f6ef7}\n h1{font-size:6rem;font-weight:800;line-height:1;background:linear-gradient(135deg,#4f6ef7,#a78bfa);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;margin-bottom:.5rem}\n h2{font-size:1.25rem;font-weight:600;color:#cbd5e1;margin-bottom:.75rem}\n p{font-size:.9rem;color:#64748b;line-height:1.6;margin-bottom:2rem}\n a{display:inline-flex;align-items:center;gap:.4rem;background:#4f6ef7;color:#fff;text-decoration:none;padding:.6rem 1.25rem;border-radius:.5rem;font-size:.875rem;font-weight:500;transition:background .15s}\n a:hover{background:#3b5ce6}\n a svg{width:14px;height:14px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}\n</style>\n</head>\n<body>\n<div class=\"card\">\n <div class=\"badge\">\n <svg viewBox=\"0 0 16 16\"><path d=\"M8 1a7 7 0 100 14A7 7 0 008 1zm0 3a1 1 0 110 2 1 1 0 010-2zm1 7H7V7h2v4z\"/></svg>\n Consenti\n </div>\n <h1>404</h1>\n <h2>Page not found</h2>\n <p>The admin dashboard is not enabled on this instance.<br>Use the API or enable <code style=\"background:#1e2330;padding:.1rem .35rem;border-radius:.25rem;font-size:.8rem\">dashboard: true</code> in your config.</p>\n <a href=\"${docsHref}\">\n <svg viewBox=\"0 0 24 24\"><path d=\"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z\"/><polyline points=\"14 2 14 8 20 8\"/><line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\"/><line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\"/><polyline points=\"10 9 9 9 8 9\"/></svg>\n View API Documentation\n </a>\n</div>\n</body>\n</html>`\n return new Response(html, { status: 404, headers: { 'Content-Type': 'text/html; charset=utf-8' } })\n}\n\nfunction buildFetchRouter(\n basePath: string,\n groups: RouteGroup[],\n rateLimiter: RateLimiter | null,\n): (request: Request) => Promise<Response> {\n const entries: RouteEntry[] = []\n\n for (const group of groups) {\n for (const [key, handler] of Object.entries(group.routes)) {\n const spaceIdx = key.indexOf(' ')\n const method = key.slice(0, spaceIdx).toUpperCase()\n const path = key.slice(spaceIdx + 1)\n const { pattern, paramNames } = compilePath(`${group.prefix}${path}`)\n entries.push({ method, pattern, paramNames, handler, rateLimit: group.rateLimit ?? false })\n }\n }\n\n return async (request: Request): Promise<Response> => {\n const corsResponse = handleCors(request)\n if (corsResponse) return corsResponse\n\n const url = new URL(request.url)\n const pathname = url.pathname\n const method = request.method.toUpperCase()\n\n if (rateLimiter) {\n const matched = entries.find(e => e.rateLimit && pathname.match(e.pattern))\n if (matched) {\n const ip = request.headers.get('x-real-ip') ?? ''\n if (!rateLimiter.checkRequest(ip)) {\n return withCors(errorResponse(429, 'Too Many Requests'), request)\n }\n }\n }\n\n for (const entry of entries) {\n if (entry.method !== method) continue\n const match = pathname.match(entry.pattern)\n if (!match) continue\n const params: Record<string, string> = {}\n entry.paramNames.forEach((name, i) => {\n const val = match[i + 1]\n if (val != null) params[name] = val\n })\n const response = await entry.handler(request, params)\n return addSecurityHeaders(withCors(response, request))\n }\n\n const isUiPath =\n pathname.startsWith(basePath) &&\n !pathname.startsWith(`${basePath}/api/`) &&\n !pathname.startsWith(`${basePath}/admin/`)\n\n return addSecurityHeaders(\n withCors(isUiPath ? branded404(basePath) : errorResponse(404, 'Not Found'), request),\n )\n }\n}\n\n// ── Deep merge ────────────────────────────────────────────────────────────────\n\nfunction isPlainObj(v: unknown): v is Record<string, unknown> {\n return typeof v === 'object' && v !== null && !Array.isArray(v)\n}\n\nfunction deepMerge(\n base: Record<string, unknown>,\n override: Record<string, unknown>,\n): Record<string, unknown> {\n const result: Record<string, unknown> = { ...base }\n for (const key of Object.keys(override)) {\n const ov = override[key]\n const bv = result[key]\n if (ov !== undefined && isPlainObj(ov) && isPlainObj(bv)) {\n result[key] = deepMerge(bv, ov)\n } else if (ov !== undefined) {\n result[key] = ov\n }\n }\n return result\n}\n\n// ── Default config ────────────────────────────────────────────────────────────\n\nconst DEFAULT_CONFIG: ConsentiServerConfig = {\n dashboard: true,\n basePath: process.env['CONSENTI_BASE_PATH'] ?? '/consenti',\n ...(process.env['CONSENTI_MAX_BODY_SIZE'] ? { maxBodySize: Number(process.env['CONSENTI_MAX_BODY_SIZE']) } : {}),\n storage: {\n driver: (process.env['CONSENTI_DB_DRIVER'] as StorageConfig['driver'] | undefined) ?? 'json',\n path: process.env['CONSENTI_DB_PATH'] ?? './consenti-data.json',\n ...(process.env['CONSENTI_DB_URI'] ? { uri: process.env['CONSENTI_DB_URI'] } : {}),\n ...(process.env['CONSENTI_DB_DATABASE'] ? { database: process.env['CONSENTI_DB_DATABASE'] } : {}),\n ...(process.env['CONSENTI_DB_HOST'] ? { host: process.env['CONSENTI_DB_HOST'] } : {}),\n ...(process.env['CONSENTI_DB_PORT'] ? { port: Number(process.env['CONSENTI_DB_PORT']) } : {}),\n ...(process.env['CONSENTI_DB_USER'] ? { user: process.env['CONSENTI_DB_USER'] } : {}),\n ...(process.env['CONSENTI_DB_PASSWORD'] ? { password: process.env['CONSENTI_DB_PASSWORD'] } : {}),\n },\n auth: {\n mode: 'local',\n adminEmail: process.env['CONSENTI_ADMIN_EMAIL'] ?? 'user@consenti.dev',\n adminPassword: process.env['CONSENTI_ADMIN_PASSWORD'] ?? 'Consenti@123',\n ...(process.env['CONSENTI_ADMIN_JWT_SECRET'] ? { jwtSecret: process.env['CONSENTI_ADMIN_JWT_SECRET'] } : {}),\n },\n rateLimit: {\n windowMs: process.env['CONSENTI_RATE_LIMIT_WINDOW_MS'] ? Number(process.env['CONSENTI_RATE_LIMIT_WINDOW_MS']) : 60_000,\n maxRequests: process.env['CONSENTI_RATE_LIMIT_MAX_REQUESTS'] ? Number(process.env['CONSENTI_RATE_LIMIT_MAX_REQUESTS']) : 60,\n },\n branding: {\n appLogoPath: \"./logo-dark.svg\",\n appName: \"Consenti\",\n hidePoweredBy: false,\n }\n}\n\n// ── Factory ────────────────────────────────────────────────────────────────────\n\nfunction createStorageAdapter(config: NonNullable<ConsentiServerConfig['storage']>): StorageAdapter {\n switch (config.driver) {\n case 'mongodb': return new MongoDBAdapter(config)\n case 'mysql': return new MySQLAdapter(config)\n case 'postgresql': return new PostgreSQLAdapter(config)\n case 'node:sqlite': return new NodeSqliteBuiltinAdapter(config)\n case 'better-sqlite3':\n case 'sqlite': return new BetterSqlite3Adapter(config)\n case 'node-sqlite3-wasm': new NodeSqlite3WasmAdapter(config)\n case 'json':\n default: return new JsonFileAdapter(config)\n }\n}\n\nexport function createConsenti(userConfig: ConsentiServerConfig) {\n const config = deepMerge(\n DEFAULT_CONFIG as unknown as Record<string, unknown>,\n userConfig as unknown as Record<string, unknown>,\n ) as ConsentiServerConfig\n\n if (!userConfig.storage) {\n console.warn('[Consenti] No storage config — using node-sqlite3-wasm (SQLite WASM) at ./consenti-data.db. Switch to a database driver for production.')\n }\n if (!userConfig.auth && !process.env['CONSENTI_ADMIN_PASSWORD']) {\n console.warn('[Consenti] No auth config or CONSENTI_ADMIN_PASSWORD env var — using demo credentials. Set CONSENTI_ADMIN_EMAIL and CONSENTI_ADMIN_PASSWORD before going to production.')\n }\n\n const storageConfig = config.storage!\n const authConfig = config.auth!\n\n const storagePaths = resolveStoragePaths(\n storageConfig.path ?? './consenti-data',\n storageConfig.driver ?? 'json',\n )\n const profilesDir = storagePaths.profilesDir\n\n const storage = createStorageAdapter(storageConfig)\n const eventBus = new EventEmitter()\n\n const profileRepo = new ProfileRepo(storage)\n const consentRepo = new ConsentRepo(storage)\n const visitorRepo = new VisitorRepo(storage)\n const auditRepo = new AuditRepo(storage)\n const userRepo = new UserRepo(storage)\n\n const pluginEngine = new PluginEngine()\n if (config.plugins?.length) pluginEngine.register(config.plugins)\n\n const compliance = config.compliance ?? {}\n const complianceType = compliance.type ?? 'auto'\n const needsGeo = complianceType === 'auto'\n\n const localeCache = (config as { localeJsonCache?: { enabled?: boolean; dir?: string } }).localeJsonCache?.enabled\n ? new LocaleJsonCacheService((config as { localeJsonCache?: { dir?: string } }).localeJsonCache!.dir!)\n : undefined\n\n const geoResolver = needsGeo\n ? new GeoResolverService(compliance.geoDataProvider ?? 'default', EMBEDDED_COMPLIANCE_MAP)\n : undefined\n\n if (complianceType === 'auto' && !compliance.geoDataProvider) {\n console.info(\"[Consenti] compliance.geoDataProvider not set — defaulting to timezone+language heuristic\")\n }\n if (complianceType !== 'auto' && compliance.geoDataProvider) {\n console.warn('[Consenti] compliance.geoDataProvider is ignored when compliance.type is a fixed group')\n }\n\n const profileService = new ProfileService(profileRepo, auditRepo, 'default', storage, eventBus, localeCache, profilesDir, config.handleCache, config.s3Api)\n const visitorService = new VisitorService(visitorRepo, 'default', eventBus)\n const consentService = new ConsentService(\n consentRepo, visitorRepo, profileRepo, auditRepo, 'default', config.compliance,\n pluginEngine, eventBus, config.tcf,\n )\n const userService = new UserService(userRepo, auditRepo)\n\n const adminSecret = authConfig.jwtSecret ?? ''\n const localAuth = new LocalAuth(storage, adminSecret)\n\n const rl = config.rateLimit!\n const rateLimiter = rl.enabled === false\n ? null\n : new RateLimiter(rl.windowMs!, rl.maxRequests!)\n const authLimiter = new RateLimiter(15 * 60_000, 10)\n\n const multiTenantEnabled = config.multiTenant?.enabled === true\n const resolveTenantId = multiTenantEnabled\n ? (req: Request) => resolveTenant(req, storage, 'default')\n : async (_req: Request) => 'default'\n\n const basePath = config.basePath!\n const apiBase = `${basePath}/api/v1`\n const adminBase = `${basePath}/admin`\n const docsPath = `${basePath}/api`\n\n const dashboardEnabled = !!config.dashboard\n const dashboardDir = join(DIST_DIR, 'dashboard')\n\n const configScript = dashboardEnabled\n ? buildConsentiConfigScript(\n buildConsentiRuntimeConfig(dashboardDir, basePath, config.branding, config.compliance),\n )\n : ''\n\n const swaggerHtml = `<!DOCTYPE html><html><head><title>Consenti API Docs</title>\n<link rel=\"stylesheet\" href=\"https://unpkg.com/swagger-ui-dist@5.17.14/swagger-ui.css\" crossorigin=\"anonymous\"></head>\n<body><div id=\"swagger-ui\"></div>\n<script src=\"https://unpkg.com/swagger-ui-dist@5.17.14/swagger-ui-bundle.js\" crossorigin=\"anonymous\"></script>\n<script src=\"https://unpkg.com/swagger-ui-dist@5.17.14/swagger-ui-standalone-preset.js\" crossorigin=\"anonymous\"></script>\n<script>SwaggerUIBundle({urls:[{url:'${docsPath}/openapi.json',name:'Public API (/consenti/api)'},{url:'${docsPath}/openapi-admin.json',name:'Admin API (/consenti/admin)'}],'urls.primaryName':'Public API (/consenti/api)',dom_id:'#swagger-ui',presets:[SwaggerUIBundle.presets.apis,SwaggerUIStandalonePreset],layout:'StandaloneLayout'})</script>\n</body></html>`\n\n const robotsTxt = `User-agent: *\\nDisallow: ${basePath}/\\n`\n\n const fetchRouter = buildFetchRouter(\n basePath,\n [\n {\n prefix: docsPath,\n rateLimit: false,\n routes: {\n 'GET /docs': async () => new Response(swaggerHtml, { headers: { 'Content-Type': 'text/html; charset=utf-8' } }),\n 'GET /openapi.json': async () => new Response(JSON.stringify(OPENAPI_PUBLIC_SPEC, null, 2), { headers: { 'Content-Type': 'application/json' } }),\n 'GET /openapi-admin.json': async () => new Response(JSON.stringify(OPENAPI_ADMIN_SPEC, null, 2), { headers: { 'Content-Type': 'application/json' } }),\n },\n },\n {\n prefix: '',\n rateLimit: false,\n routes: {\n 'GET /robots.txt': async () => new Response(robotsTxt, { headers: { 'Content-Type': 'text/plain; charset=utf-8' } }),\n },\n },\n {\n prefix: apiBase,\n rateLimit: true,\n routes: {\n ...buildProfileRoutes(profileService, geoResolver, profilesDir, apiBase),\n ...buildConsentRoutes(consentService, visitorService, profileService, resolveTenantId),\n },\n },\n {\n prefix: adminBase,\n rateLimit: false,\n routes: {\n 'GET /widget.js': async () => serveDistFile(join(DIST_DIR, 'widget', 'widget.js'), 'application/javascript; charset=utf-8'),\n 'GET /widget.css': async () => serveDistFile(join(DIST_DIR, 'widget', 'widget.css'), 'text/css; charset=utf-8'),\n ...buildAdminAuthRoutes(localAuth, storage, authConfig, adminSecret, authLimiter),\n ...buildAdminProfileRoutes(profileService, storage, authConfig, adminSecret),\n ...buildAdminConsentRoutes(storage, authConfig, adminSecret),\n ...buildAdminVisitorRoutes(storage, authConfig, adminSecret),\n ...buildAdminUserRoutes(userService, storage, authConfig, adminSecret),\n ...buildAdminRoleRoutes(storage, authConfig, adminSecret),\n ...buildAdminAuditRoutes(storage, authConfig, adminSecret),\n ...buildAdminStatsRoutes(storage, authConfig, adminSecret),\n ...buildAdminExportRoutes(storage, authConfig, adminSecret),\n ...buildAdminApiKeyRoutes(storage, authConfig, adminSecret),\n ...buildAdminTenantRoutes(storage, authConfig, adminSecret),\n ...buildAdminTcfRoutes(storage, authConfig, adminSecret),\n ...buildAdminCookieTemplateRoutes(storage, authConfig, adminSecret),\n ...buildAdminUITemplateRoutes(storage, authConfig, adminSecret),\n ...buildAdminAnalyticsRoutes(storage, authConfig, adminSecret),\n },\n },\n ],\n rateLimiter,\n )\n\n let retentionTimer: ReturnType<typeof setInterval> | null = null\n\n // Resolves after storage.connect() + bootstrap() complete — consumers can await\n // this before accepting requests to guarantee the admin user already exists.\n let resolveReady!: () => void\n let rejectReady!: (err: unknown) => void\n const ready = new Promise<void>((res, rej) => { resolveReady = res; rejectReady = rej })\n\n storage\n .connect()\n .then(async () => {\n if (authConfig.mode === 'local' && authConfig.adminEmail && authConfig.adminPassword) {\n await localAuth.bootstrap(authConfig.adminEmail, authConfig.adminPassword)\n }\n await pluginEngine.initialize({ storage, config })\n eventBus.emit('ready')\n resolveReady()\n\n if (config.tcf?.enabled) {\n startGvlRefresh()\n }\n\n if (config.dataRetention?.purgeAfterDays) {\n const days = config.dataRetention.purgeAfterDays\n const purge = () => storage.purgeExpiredConsents(days)\n .then(n => { if (n > 0) console.warn(`[consenti] Purged ${n} consent records older than ${days} days`) })\n .catch((err: unknown) => console.warn('[consenti] Data retention purge failed:', err))\n void purge()\n retentionTimer = setInterval(() => { void purge() }, 24 * 60 * 60_000)\n }\n })\n .catch((err: unknown) => {\n console.warn('[consenti] Storage connection failed:', err)\n rejectReady(err)\n })\n\n async function nodeHandler(req: IncomingMessage, res: ServerResponse): Promise<void> {\n try {\n const rawProto = req.headers['x-forwarded-proto']\n const proto = rawProto === 'https' ? 'https' : 'http'\n const host = req.headers['host'] ?? 'localhost'\n const url = new URL(req.url ?? '/', `${proto}://${host}`)\n\n if (dashboardEnabled && url.pathname.startsWith(basePath)) {\n const served = await tryServeDashboard(url.pathname, basePath, dashboardDir, res, configScript)\n if (served) return\n }\n\n const request = await nodeRequestToFetch(req, config.maxBodySize, config.trustedProxies)\n const response = await fetchRouter(request)\n\n if (url.pathname === `${basePath}/api/openapi.json`) {\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify(OPENAPI_PUBLIC_SPEC, null, 2))\n return\n }\n\n if (url.pathname === `${basePath}/api/openapi-admin.json`) {\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify(OPENAPI_ADMIN_SPEC, null, 2))\n return\n }\n\n if (url.pathname === `${basePath}/api/docs`) {\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' })\n res.end(swaggerHtml)\n return\n }\n\n if (\n response.status === 404 &&\n dashboardEnabled &&\n url.pathname.startsWith(basePath) &&\n !url.pathname.startsWith(basePath + '/api/') &&\n !url.pathname.startsWith(basePath + '/admin/')\n ) {\n try {\n const html = await readFile(join(dashboardDir, 'index.html'))\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' })\n res.end(injectConfigScript(html, configScript))\n return\n } catch {\n // dashboard not built — fall through\n }\n }\n\n await fetchResponseToNode(response, res)\n } catch (err) {\n if (!res.headersSent) {\n if (err instanceof PayloadTooLargeError) {\n res.writeHead(413, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ error: 'Payload Too Large' }))\n } else {\n res.writeHead(500, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ error: 'Internal Server Error' }))\n }\n }\n }\n }\n\n function router(\n req: IncomingMessage,\n res: ServerResponse,\n next: (err?: unknown) => void,\n ): void {\n nodeHandler(req, res)\n .then(() => { if (!res.writableEnded) next() })\n .catch(next)\n }\n\n function handler(req: IncomingMessage, res: ServerResponse): Promise<void> {\n return nodeHandler(req, res)\n }\n\n const fastifyHandler = async (\n fastify: {\n all: (\n path: string,\n handler: (req: { raw: IncomingMessage }, reply: { raw: ServerResponse; hijack: () => void }) => Promise<void>,\n ) => void\n },\n _opts: unknown,\n ): Promise<void> => {\n fastify.all('/*', async (request, reply) => {\n await nodeHandler(request.raw, reply.raw)\n reply.hijack()\n })\n }\n Object.defineProperty(fastifyHandler, Symbol.for('skip-override'), { value: true })\n\n const fetchHandler = async (request: Request): Promise<Response> => {\n if (dashboardEnabled) {\n const url = new URL(request.url)\n const pathname = url.pathname\n if (pathname.startsWith(basePath)) {\n const rel = pathname.slice(basePath.length) || '/'\n if (!rel.startsWith('/api/') && !rel.startsWith('/admin/')) {\n const target = extname(rel) ? join(dashboardDir, rel) : join(dashboardDir, 'index.html')\n if (!target.startsWith(dashboardDir)) {\n return new Response('Forbidden', { status: 403 })\n }\n try {\n const raw = await readFile(target)\n const ext = extname(target).toLowerCase()\n const isHtml = ext === '.html' || ext === ''\n const ct = MIME[ext] ?? 'application/octet-stream'\n const body = isHtml ? injectConfigScript(raw, configScript) : raw\n return new Response(body, { headers: { 'Content-Type': ct } })\n } catch {\n try {\n const html = await readFile(join(dashboardDir, 'index.html'))\n return new Response(injectConfigScript(html, configScript), {\n headers: { 'Content-Type': 'text/html; charset=utf-8' },\n })\n } catch {\n return new Response(\n 'Dashboard not built. Run: npm run build --workspace=apps/api',\n { status: 404, headers: { 'Content-Type': 'text/plain' } },\n )\n }\n }\n }\n }\n }\n return fetchRouter(request)\n }\n\n const honoApp = { fetch: fetchHandler }\n\n const services = {\n profile: profileService,\n consent: consentService,\n visitor: visitorService,\n user: userService,\n }\n\n return {\n router,\n handler,\n fastifyHandler,\n honoApp,\n services,\n storage: storage as StorageAdapter,\n eventBus,\n ready,\n destroy: async () => {\n if (retentionTimer) clearInterval(retentionTimer)\n if (config.tcf?.enabled) stopGvlRefresh()\n await pluginEngine.destroy()\n },\n }\n}\n\nexport { SQLiteAdapter } from './storage/sqlite/sqlite.adapter'\nexport { MongoDBAdapter } from './storage/mongodb/mongodb.adapter'\nexport { MySQLAdapter } from './storage/mysql/mysql.adapter'\nexport { PostgreSQLAdapter } from './storage/postgresql/postgresql.adapter'\n\nexport type {\n ConsentiServerConfig,\n BrandingConfig,\n StorageAdapter,\n Profile,\n ConsentDbRecord,\n Visitor,\n AdminUser,\n Role,\n Permission,\n AuditLog,\n ConsentVerifyResult,\n SafeAdminUser,\n} from '@consenti/types'\n","// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","import type {\n ConsentiServerPlugin,\n CreateConsentInput,\n UpdateConsentInput,\n ConsentDbRecord,\n Profile,\n CreateUserInput,\n AdminUser,\n PluginContext,\n} from '@consenti/types'\n\nexport class PluginEngine {\n private plugins: ConsentiServerPlugin[] = []\n\n register(plugins: ConsentiServerPlugin[]): void {\n this.plugins = plugins\n }\n\n async initialize(context: PluginContext): Promise<void> {\n for (const plugin of this.plugins) {\n try { await plugin.initialize?.(context) }\n catch (err) { console.warn(`[Consenti] Plugin \"${plugin.name}\" initialize failed:`, err) }\n }\n }\n\n async destroy(): Promise<void> {\n for (const plugin of this.plugins) {\n try { await plugin.destroy?.() }\n catch (err) { console.warn(`[Consenti] Plugin \"${plugin.name}\" destroy failed:`, err) }\n }\n }\n\n async runBeforeConsentSave(data: CreateConsentInput): Promise<CreateConsentInput> {\n let result = data\n for (const plugin of this.plugins) {\n if (!plugin.beforeConsentSave) continue\n try { result = await plugin.beforeConsentSave(result) }\n catch (err) { console.warn(`[Consenti] Plugin \"${plugin.name}\" beforeConsentSave failed:`, err) }\n }\n return result\n }\n\n async runAfterConsentSave(record: ConsentDbRecord): Promise<void> {\n for (const plugin of this.plugins) {\n if (!plugin.afterConsentSave) continue\n try { await plugin.afterConsentSave(record) }\n catch (err) { console.warn(`[Consenti] Plugin \"${plugin.name}\" afterConsentSave failed:`, err) }\n }\n }\n\n async runBeforeConsentUpdate(data: UpdateConsentInput): Promise<UpdateConsentInput> {\n let result = data\n for (const plugin of this.plugins) {\n if (!plugin.beforeConsentUpdate) continue\n try { result = await plugin.beforeConsentUpdate(result) }\n catch (err) { console.warn(`[Consenti] Plugin \"${plugin.name}\" beforeConsentUpdate failed:`, err) }\n }\n return result\n }\n\n async runAfterConsentUpdate(record: ConsentDbRecord): Promise<void> {\n for (const plugin of this.plugins) {\n if (!plugin.afterConsentUpdate) continue\n try { await plugin.afterConsentUpdate(record) }\n catch (err) { console.warn(`[Consenti] Plugin \"${plugin.name}\" afterConsentUpdate failed:`, err) }\n }\n }\n\n async runAfterProfileFetch(profile: Profile): Promise<Profile> {\n let result = profile\n for (const plugin of this.plugins) {\n if (!plugin.afterProfileFetch) continue\n try { result = await plugin.afterProfileFetch(result) }\n catch (err) { console.warn(`[Consenti] Plugin \"${plugin.name}\" afterProfileFetch failed:`, err) }\n }\n return result\n }\n\n async runBeforeUserCreate(data: CreateUserInput): Promise<CreateUserInput> {\n let result = data\n for (const plugin of this.plugins) {\n if (!plugin.beforeUserCreate) continue\n try { result = await plugin.beforeUserCreate(result) }\n catch (err) { console.warn(`[Consenti] Plugin \"${plugin.name}\" beforeUserCreate failed:`, err) }\n }\n return result\n }\n\n async runAfterUserCreate(user: AdminUser): Promise<void> {\n for (const plugin of this.plugins) {\n if (!plugin.afterUserCreate) continue\n try { await plugin.afterUserCreate(user) }\n catch (err) { console.warn(`[Consenti] Plugin \"${plugin.name}\" afterUserCreate failed:`, err) }\n }\n }\n}\n","/**\n * Utilities for materialising server config into the dashboard SPA.\n *\n * Data is injected as an inline <script> that writes window.__CONSENTI_CONFIG__\n * using Object.defineProperty with writable:false + configurable:false, then\n * deep-freezes the value so neither the object nor any nested property can be\n * mutated from the browser.\n */\n\nimport { copyFileSync, existsSync, mkdirSync } from 'node:fs'\nimport { extname, join } from 'node:path'\nimport type { BrandingConfig, ComplianceConfig, ConsentiRuntimeConfig } from '@consenti/types'\n\nfunction resolveappLogoPath(dashboardDir: string, branding: BrandingConfig): string | null {\n const { appLogoPath } = branding\n if (!appLogoPath) return null\n\n if (/^(https?:\\/\\/|data:)/i.test(appLogoPath)) return appLogoPath\n\n if (existsSync(appLogoPath)) {\n const ext = extname(appLogoPath) || '.png'\n const destName = `logo${ext}`\n try {\n if (!existsSync(dashboardDir)) mkdirSync(dashboardDir, { recursive: true })\n copyFileSync(appLogoPath, join(dashboardDir, destName))\n return `./logo${ext}`\n } catch {\n console.warn(`[Consenti] branding: could not copy logo from \"${appLogoPath}\" — logo will not be shown`)\n return null\n }\n }\n\n console.warn(`[Consenti] branding: appLogoPath \"${appLogoPath}\" does not exist — logo will not be shown`)\n return null\n}\n\nexport function buildConsentiRuntimeConfig(\n dashboardDir: string,\n basePath: string,\n branding: BrandingConfig = {},\n compliance: ComplianceConfig = {},\n): ConsentiRuntimeConfig {\n const resolvedCompliance: ConsentiRuntimeConfig['compliance'] = {}\n if (compliance.type !== undefined) resolvedCompliance.type = compliance.type\n if (compliance.gpc !== undefined) resolvedCompliance.gpc = compliance.gpc\n\n return {\n appName: branding.appName ?? 'Consenti',\n appLogoPath: branding?.appLogoPath ?? \"/logo-dark.svg\", // resolveappLogoPath(dashboardDir, branding),\n hidePoweredBy: branding.hidePoweredBy ?? false,\n basePath,\n compliance: resolvedCompliance,\n }\n}\n\nexport function buildConsentiConfigScript(cfg: ConsentiRuntimeConfig): string {\n // Escape </script> to prevent early tag termination, then emit a self-contained IIFE\n // that locks the config via Object.defineProperty + deep-freeze.\n const json = JSON.stringify(cfg).replace(/<\\/script>/gi, '<\\\\/script>')\n return `<script>(function(){` +\n `function d(o){if(o&&typeof o==='object')Object.keys(o).forEach(function(k){d(o[k])});return Object.freeze(o)}` +\n `Object.defineProperty(window,'__CONSENTI_CONFIG__',{value:d(${json}),writable:false,configurable:false,enumerable:true})` +\n `})()</script>`\n}\n\nexport function injectConfigScript(html: Uint8Array, script: string): string {\n const str = Buffer.from(html).toString('utf-8')\n return str.includes('</head>')\n ? str.replace('</head>', `${script}</head>`)\n : str.replace('</body>', `${script}</body>`)\n}\n","const GVL_URL = 'https://vendor-list.consensu.org/v3/vendor-list.json'\nconst REFRESH_MS = 7 * 24 * 60 * 60 * 1000\n\nexport interface GvlPurpose {\n id: number\n name: string\n description: string\n}\n\nexport interface GvlVendor {\n id: number\n name: string\n purposes?: number[]\n legIntPurposes?: number[]\n flexiblePurposes?: number[]\n specialPurposes?: number[]\n features?: number[]\n specialFeatures?: number[]\n}\n\nexport interface GvlData {\n gvlSpecificationVersion: number\n vendorListVersion: number\n vendors: Record<string, GvlVendor>\n purposes: Record<string, GvlPurpose>\n}\n\nlet cachedGvl: GvlData | null = null\nlet lastFetched = 0\nlet refreshTimer: ReturnType<typeof setInterval> | null = null\n\nfunction isGvlData(d: unknown): d is GvlData {\n return typeof d === 'object' && d !== null &&\n 'vendors' in d && 'purposes' in d &&\n typeof (d as GvlData).vendors === 'object' &&\n typeof (d as GvlData).purposes === 'object'\n}\n\nexport async function getGvl(): Promise<GvlData | null> {\n if (cachedGvl && Date.now() - lastFetched < REFRESH_MS) return cachedGvl\n try {\n const res = await fetch(GVL_URL, { signal: AbortSignal.timeout(15_000) })\n if (!res.ok) return cachedGvl\n const data = await res.json()\n if (!isGvlData(data)) return cachedGvl\n cachedGvl = data\n lastFetched = Date.now()\n return cachedGvl\n } catch {\n return cachedGvl\n }\n}\n\nexport function startGvlRefresh(): void {\n if (refreshTimer) return\n void getGvl()\n refreshTimer = setInterval(() => { void getGvl() }, REFRESH_MS)\n}\n\nexport function stopGvlRefresh(): void {\n if (!refreshTimer) return\n clearInterval(refreshTimer)\n refreshTimer = null\n}\n","const SHARED_SCHEMAS = {\n ConsentRecord: {\n type: 'object',\n properties: {\n id: { type: 'string' },\n visitorId: { type: 'string' },\n profileId: { type: 'string' },\n profileVersion: { type: 'integer' },\n locale: { type: 'string' },\n consentJson: { type: 'object', additionalProperties: { type: 'string', enum: ['granted', 'denied', 'objected'] } },\n gpcDetected: { type: 'boolean' },\n source: { type: 'string', enum: ['banner', 'api', 'import'] },\n ageVerified: { type: 'boolean' },\n tcfString: { type: 'string' },\n createdAt: { type: 'string', format: 'date-time' },\n updatedAt: { type: 'string', format: 'date-time' },\n },\n },\n CreateConsentInput: {\n type: 'object',\n required: ['visitorId', 'profileId', 'consentJson'],\n properties: {\n visitorId: { type: 'string' },\n profileId: { type: 'string' },\n consentJson: { type: 'object', additionalProperties: { type: 'string' } },\n gpcDetected: { type: 'boolean', default: false },\n source: { type: 'string', enum: ['banner', 'api', 'import'], default: 'banner' },\n ageVerified: { type: 'boolean' },\n parentalConsentToken: { type: 'string' },\n tcfString: { type: 'string' },\n },\n },\n}\n\nexport const OPENAPI_PUBLIC_SPEC = {\n openapi: '3.1.0',\n info: {\n title: 'Consenti Public API',\n version: '0.1.0',\n description: 'Visitor-facing endpoints for reading consent profiles and submitting/verifying consent. Rate-limited; no authentication required.',\n license: { name: 'Apache 2.0', url: 'https://www.apache.org/licenses/LICENSE-2.0' },\n },\n servers: [\n { url: '/consenti/api', description: 'Consenti Public API' },\n ],\n paths: {\n '/v1/profiles/{id}': {\n get: {\n tags: ['Profile'],\n summary: 'Get profile in its default locale',\n description: 'Returns the resolved profile with banner and modal content for the profile\\'s default locale. Includes `currentLocale`, `locales`, `cookies`, `mainBanner`, `preferenceModal`, and optionally `gpcBanner`.',\n parameters: [\n { name: 'id', in: 'path', required: true, schema: { type: 'string' } },\n ],\n responses: {\n '200': { description: 'Resolved profile for the default locale' },\n '404': { description: 'Profile not found' },\n },\n },\n },\n '/v1/profiles/{id}/{locale}': {\n get: {\n tags: ['Profile'],\n summary: 'Get profile resolved for a specific locale',\n description: 'Same response shape as `GET /v1/profiles/{id}` but resolved for the requested locale, falling back to the default locale for any missing translations.',\n parameters: [\n { name: 'id', in: 'path', required: true, schema: { type: 'string' } },\n { name: 'locale', in: 'path', required: true, schema: { type: 'string', example: 'fr' } },\n ],\n responses: {\n '200': { description: 'Resolved profile for the requested locale' },\n '404': { description: 'Profile not found' },\n },\n },\n },\n '/v1/consent': {\n post: {\n tags: ['Consent'],\n summary: 'Submit consent',\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: { $ref: '#/components/schemas/CreateConsentInput' },\n },\n },\n },\n responses: {\n '200': { description: 'Consent created or updated', content: { 'application/json': { schema: { $ref: '#/components/schemas/ConsentRecord' } } } },\n '400': { description: 'Validation error' },\n },\n },\n },\n '/v1/consent/{visitorId}': {\n get: {\n tags: ['Consent'],\n summary: 'Get consent for visitor',\n parameters: [{ name: 'visitorId', in: 'path', required: true, schema: { type: 'string' } }],\n responses: {\n '200': { description: 'Consent record', content: { 'application/json': { schema: { $ref: '#/components/schemas/ConsentRecord' } } } },\n '404': { description: 'Not found' },\n },\n },\n put: {\n tags: ['Consent'],\n summary: 'Update consent',\n parameters: [{ name: 'visitorId', in: 'path', required: true, schema: { type: 'string' } }],\n responses: { '200': { description: 'Updated consent' } },\n },\n delete: {\n tags: ['Consent'],\n summary: 'GDPR erasure — delete all consent data for visitor',\n parameters: [{ name: 'visitorId', in: 'path', required: true, schema: { type: 'string' } }],\n responses: { '200': { description: 'Erased successfully' } },\n },\n },\n '/v1/consent/{visitorId}/verify': {\n get: {\n tags: ['Consent'],\n summary: 'Verify consent validity',\n parameters: [{ name: 'visitorId', in: 'path', required: true, schema: { type: 'string' } }],\n responses: { '200': { description: 'Verification result' } },\n },\n },\n },\n components: {\n schemas: SHARED_SCHEMAS,\n },\n}\n\nexport const OPENAPI_ADMIN_SPEC = {\n openapi: '3.1.0',\n info: {\n title: 'Consenti Admin API',\n version: '0.1.0',\n description: 'Authenticated endpoints for managing profiles, consent records, users, analytics, and exports. All routes (except `/auth/login`) require `Authorization: Bearer <JWT>`. Obtain a token via `POST /auth/login`.',\n license: { name: 'Apache 2.0', url: 'https://www.apache.org/licenses/LICENSE-2.0' },\n },\n servers: [\n { url: '/consenti/admin', description: 'Consenti Admin API' },\n ],\n paths: {\n // ── Auth ──────────────────────────────────────────────────────────────\n '/auth/login': {\n post: {\n tags: ['Auth'],\n summary: 'Login with email + password',\n requestBody: { required: true, content: { 'application/json': { schema: { type: 'object', properties: { email: { type: 'string' }, password: { type: 'string' } } } } } },\n responses: { '200': { description: 'JWT token' } },\n },\n },\n '/auth/me': {\n get: {\n tags: ['Auth'],\n summary: 'Get current user',\n security: [{ BearerAuth: [] }],\n responses: { '200': { description: 'Current admin user info' } },\n },\n },\n '/auth/logout': {\n post: {\n tags: ['Auth'],\n summary: 'Invalidate session',\n security: [{ BearerAuth: [] }],\n responses: { '200': { description: 'Logged out' } },\n },\n },\n '/auth/oidc/authorize': {\n get: {\n tags: ['Auth'],\n summary: 'Start OIDC authorization (PKCE)',\n responses: { '302': { description: 'Redirect to OIDC provider' } },\n },\n },\n '/auth/oidc/callback': {\n get: {\n tags: ['Auth'],\n summary: 'OIDC callback — exchange code for token',\n responses: { '200': { description: 'JWT token' } },\n },\n },\n '/auth/saml/metadata': {\n get: {\n tags: ['Auth'],\n summary: 'SAML SP metadata XML',\n responses: { '200': { description: 'SAML metadata XML', content: { 'application/xml': {} } } },\n },\n },\n '/auth/saml/acs': {\n post: {\n tags: ['Auth'],\n summary: 'SAML Assertion Consumer Service',\n responses: { '200': { description: 'JWT token' } },\n },\n },\n '/auth/totp/setup': {\n post: {\n tags: ['Auth'],\n summary: 'Setup TOTP MFA',\n security: [{ BearerAuth: [] }],\n responses: { '200': { description: 'TOTP secret and QR URL' } },\n },\n },\n '/auth/totp/verify': {\n post: {\n tags: ['Auth'],\n summary: 'Verify and enable TOTP',\n security: [{ BearerAuth: [] }],\n responses: { '200': { description: 'TOTP enabled' } },\n },\n },\n // ── Profiles ──────────────────────────────────────────────────────────\n '/profiles': {\n get: {\n tags: ['Profiles'],\n summary: 'List profiles',\n security: [{ BearerAuth: [] }],\n responses: { '200': { description: 'Array of profiles' } },\n },\n post: {\n tags: ['Profiles'],\n summary: 'Create profile',\n security: [{ BearerAuth: [] }],\n responses: { '201': { description: 'Created profile' } },\n },\n },\n // ── Consents ──────────────────────────────────────────────────────────\n '/consents': {\n get: {\n tags: ['Consents'],\n summary: 'List consent records',\n security: [{ BearerAuth: [] }],\n parameters: [\n { name: 'page', in: 'query', schema: { type: 'integer' } },\n { name: 'profileId', in: 'query', schema: { type: 'string' } },\n { name: 'from', in: 'query', schema: { type: 'string', format: 'date' } },\n { name: 'to', in: 'query', schema: { type: 'string', format: 'date' } },\n ],\n responses: { '200': { description: 'Paginated consent records' } },\n },\n },\n // ── Stats ─────────────────────────────────────────────────────────────\n '/stats/overview': {\n get: {\n tags: ['Stats'],\n summary: 'Overview statistics',\n security: [{ BearerAuth: [] }],\n responses: { '200': { description: 'Totals and acceptance rates' } },\n },\n },\n '/stats/timeline': {\n get: {\n tags: ['Stats'],\n summary: 'Daily consent timeline',\n security: [{ BearerAuth: [] }],\n parameters: [{ name: 'days', in: 'query', schema: { type: 'integer', default: 30 } }],\n responses: { '200': { description: 'Array of date+count' } },\n },\n },\n '/stats/countries': {\n get: {\n tags: ['Stats'],\n summary: 'Consent by country',\n security: [{ BearerAuth: [] }],\n responses: { '200': { description: 'Country counts' } },\n },\n },\n '/stats/gpc': {\n get: {\n tags: ['Stats'],\n summary: 'GPC detection stats',\n security: [{ BearerAuth: [] }],\n responses: { '200': { description: 'GPC rate and counts' } },\n },\n },\n // ── Export ────────────────────────────────────────────────────────────\n '/export/consents': {\n get: {\n tags: ['Export'],\n summary: 'Export consent records',\n security: [{ BearerAuth: [] }],\n parameters: [\n { name: 'format', in: 'query', schema: { type: 'string', enum: ['csv', 'json'] } },\n { name: 'from', in: 'query', schema: { type: 'string', format: 'date' } },\n { name: 'to', in: 'query', schema: { type: 'string', format: 'date' } },\n ],\n responses: { '200': { description: 'CSV or JSON download' } },\n },\n },\n // ── Tenants ───────────────────────────────────────────────────────────\n '/tenants': {\n get: {\n tags: ['Sites'],\n summary: 'List all sites/tenants',\n security: [{ BearerAuth: [] }],\n responses: { '200': { description: 'Array of tenants' } },\n },\n post: {\n tags: ['Sites'],\n summary: 'Create a site/tenant',\n security: [{ BearerAuth: [] }],\n requestBody: { required: true, content: { 'application/json': { schema: { type: 'object', properties: { name: { type: 'string' }, slug: { type: 'string' } }, required: ['name', 'slug'] } } } },\n responses: { '201': { description: 'Created tenant' } },\n },\n },\n '/tenants/{id}': {\n put: {\n tags: ['Sites'],\n summary: 'Update a site/tenant',\n security: [{ BearerAuth: [] }],\n parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'string' } }],\n responses: { '200': { description: 'Updated tenant' } },\n },\n delete: {\n tags: ['Sites'],\n summary: 'Delete a site/tenant',\n security: [{ BearerAuth: [] }],\n parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'string' } }],\n responses: { '200': { description: 'Deleted' } },\n },\n },\n },\n components: {\n securitySchemes: {\n BearerAuth: { type: 'http', scheme: 'bearer', bearerFormat: 'JWT' },\n },\n schemas: SHARED_SCHEMAS,\n },\n}\n","import { createHash, createHmac, randomUUID, scryptSync, randomBytes, timingSafeEqual } from 'node:crypto'\n\nexport { randomUUID }\n\nexport function randomProfileId(): string {\n return `prof_${randomBytes(20).toString('hex')}`\n}\n\nexport function hashIp(ip: string): string {\n return createHash('sha256').update(ip).digest('hex')\n}\n\nexport function hashUserAgent(ua: string): string {\n return createHash('sha256').update(ua).digest('hex')\n}\n\nexport function signHmac(payload: string, secret: string): string {\n return createHmac('sha256', secret).update(payload).digest('hex')\n}\n\nexport function verifyHmac(payload: string, signature: string, secret: string): boolean {\n const expected = Buffer.from(signHmac(payload, secret), 'hex')\n const actual = Buffer.from(signature, 'hex')\n if (expected.length !== actual.length) return false\n return timingSafeEqual(expected, actual)\n}\n\nexport function hashPassword(password: string): string {\n const salt = randomBytes(16).toString('hex')\n const hash = scryptSync(password, salt, 64).toString('hex')\n return `${salt}:${hash}`\n}\n\nexport function verifyPassword(password: string, stored: string): boolean {\n const [salt, hash] = stored.split(':')\n if (!salt || !hash) return false\n const derived = scryptSync(password, salt, 64).toString('hex')\n return timingSafeEqual(Buffer.from(hash, 'hex'), Buffer.from(derived, 'hex'))\n}\n\nexport function signJwt(payload: Record<string, unknown>, secret: string, expiresInSeconds = 3600): string {\n const now = Math.floor(Date.now() / 1000)\n const header = btoa(JSON.stringify({ alg: 'HS256', typ: 'JWT' })).replace(/=/g, '')\n const body = btoa(JSON.stringify({ ...payload, iat: now, exp: now + expiresInSeconds })).replace(/=/g, '')\n const sig = signHmac(`${header}.${body}`, secret)\n .match(/.{2}/g)!\n .map(h => String.fromCharCode(parseInt(h, 16)))\n .join('')\n const sigEncoded = btoa(sig).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '')\n return `${header}.${body}.${sigEncoded}`\n}\n\nexport function verifyJwt(token: string, secret: string): Record<string, unknown> | null {\n const parts = token.split('.')\n if (parts.length !== 3) return null\n const [header, body, sigEncoded] = parts\n if (!header || !body || !sigEncoded) return null\n const expected = signHmac(`${header}.${body}`, secret)\n const sigBytes = atob(sigEncoded.replace(/-/g, '+').replace(/_/g, '/'))\n const actualHex = Array.from(sigBytes).map(c => c.charCodeAt(0).toString(16).padStart(2, '0')).join('')\n const expectedBuf = Buffer.from(expected, 'hex')\n const actualBuf = Buffer.from(actualHex, 'hex')\n if (expectedBuf.length !== actualBuf.length || !timingSafeEqual(expectedBuf, actualBuf)) return null\n try {\n const payload = JSON.parse(atob(body)) as Record<string, unknown>\n const exp = payload['exp']\n if (typeof exp === 'number' && Date.now() / 1000 > exp) return null\n return payload\n } catch {\n return null\n }\n}\n","import { existsSync, accessSync, constants, mkdirSync } from 'node:fs'\nimport { resolve, extname, dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nexport interface StoragePaths {\n /** Full path to the adapter's DB file (inside basePath/db/). */\n dbPath: string\n /** Full path to the profiles directory (basePath/profiles/). */\n profilesDir: string\n /** Full path to the logs directory (basePath/logs/). */\n logsDir: string\n /** Resolved base directory path. */\n basePath: string\n}\n\nconst DB_FILE_NAMES: Record<string, string> = {\n 'node:sqlite': 'consenti.db',\n 'better-sqlite3': 'consenti.db',\n 'node-sqlite3-wasm': 'consenti.db',\n sqlite: 'consenti.db',\n json: 'consenti-data.json',\n mongodb: '',\n mysql: '',\n postgresql: '',\n}\n\nconst _thisDir = dirname(fileURLToPath(import.meta.url))\n\n/** Guard: path must not be inside the process's own module directory. */\nfunction isInsidePackageInstall(resolved: string): boolean {\n const nodeModulesSegment = resolved.includes('node_modules')\n const isInDist = resolved.startsWith(resolve(_thisDir, '..', '..'))\n return nodeModulesSegment || isInDist\n}\n\n/**\n * Resolves and validates the storage base directory from `config.storage.path`.\n *\n * Backward compat: if the path has a file extension (.json, .db) it is treated as a\n * legacy file path — the parent directory is used instead and a deprecation warning is logged.\n */\nexport function resolveStoragePaths(rawPath: string, driver: string): StoragePaths {\n let basePath = resolve(rawPath)\n\n const ext = extname(basePath)\n if (ext) {\n console.warn(\n `[consenti] storage.path \"${rawPath}\" looks like a file path (has extension \"${ext}\"). ` +\n `Treating parent directory as storage root. Update your config to pass a directory path.`,\n )\n basePath = dirname(basePath)\n }\n\n if (isInsidePackageInstall(basePath)) {\n throw new Error(\n `[consenti] storage.path \"${basePath}\" is inside the package installation directory. ` +\n `Choose a writable directory outside node_modules.`,\n )\n }\n\n if (!existsSync(basePath)) {\n mkdirSync(basePath, { recursive: true })\n }\n\n try {\n accessSync(basePath, constants.W_OK)\n } catch {\n throw new Error(`[consenti] storage.path \"${basePath}\" is not writable.`)\n }\n\n const dbDir = join(basePath, 'db')\n const profilesDir = join(basePath, 'profiles')\n const logsDir = join(basePath, 'logs')\n\n mkdirSync(dbDir, { recursive: true })\n mkdirSync(profilesDir, { recursive: true })\n mkdirSync(logsDir, { recursive: true })\n\n const dbFileName = DB_FILE_NAMES[driver] ?? 'consenti.db'\n const dbPath = dbFileName ? join(dbDir, dbFileName) : ''\n\n return { basePath, dbPath, profilesDir, logsDir }\n}\n","// Single source of truth for schema definitions, seed data, and SQL generation.\n// Document DBs (JSON, MongoDB) use the JS objects directly.\n// SQL DBs (SQLite, PostgreSQL, MySQL) import the generated SQL exports.\n\n// ── Schema definition types ───────────────────────────────────────────────────\n\n/** Abstract column types — each SQL dialect maps these to its native type. */\nexport type ColType =\n | 'pk' // String primary key\n | 'text' // Short-medium text (TEXT in SQLite/PG; VARCHAR(255) in MySQL)\n | 'text_sm' // Short code ≤20 (TEXT in SQLite/PG; VARCHAR(20) in MySQL)\n | 'text_md' // Medium text ≤100 (TEXT in SQLite/PG; VARCHAR(100) in MySQL)\n | 'text_geo' // Geo code ≤10 (TEXT in SQLite/PG; VARCHAR(10) in MySQL)\n | 'text_hash' // Hash string ≤64 (TEXT in SQLite/PG; VARCHAR(64) in MySQL)\n | 'longtext' // Long text (TEXT in SQLite/PG; LONGTEXT in MySQL)\n | 'json' // JSON blob (TEXT in SQLite; JSONB in PG; LONGTEXT in MySQL)\n | 'int' // Integer\n | 'bool' // Boolean (INTEGER 0/1 in SQLite; BOOLEAN in PG; TINYINT(1) in MySQL)\n | 'ts' // Timestamp with current-time default\n\nexport interface ColDef {\n n: string // column name\n t: ColType\n null?: true // nullable; omit = NOT NULL\n def?: string | number | boolean // '$now'→now(), '$arr'→'[]', '$obj'→'{}'\n unique?: true\n ref?: string // REFERENCES <ref>(id)\n onDel?: 'CASCADE'\n mysqlUpd?: true // MySQL: ON UPDATE CURRENT_TIMESTAMP\n}\n\nexport interface TableDef {\n name: string\n cols: ColDef[]\n pk?: string[] // composite primary key\n uq?: { cols: string[] }[] // composite unique constraints\n}\n\n// ── Table definitions ─────────────────────────────────────────────────────────\n\nconst tenants: TableDef = {\n name: 'tenants',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'name', t: 'text' },\n { n: 'slug', t: 'text', unique: true },\n { n: 'created_at', t: 'ts', def: '$now' },\n { n: 'updated_at', t: 'ts', def: '$now', mysqlUpd: true },\n ],\n}\n\nconst profiles: TableDef = {\n name: 'profiles',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants' },\n { n: 'name', t: 'text' },\n { n: 'default_locale', t: 'text_sm', def: 'en' },\n { n: 'version', t: 'int', def: 1 },\n { n: 'profile_json', t: 'json' },\n { n: 'created_at', t: 'ts', def: '$now' },\n { n: 'updated_at', t: 'ts', def: '$now', mysqlUpd: true },\n ],\n}\n\n// SQLite initial schema — without enterprise columns (added via ALTER TABLE in v3 migration)\nconst consentRecordsBase: TableDef = {\n name: 'consent_records',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants' },\n { n: 'visitor_id', t: 'text' },\n { n: 'profile_id', t: 'text', ref: 'profiles' },\n { n: 'profile_version', t: 'int' },\n { n: 'locale', t: 'text_sm' },\n { n: 'consent_json', t: 'json' },\n { n: 'gpc_detected', t: 'bool', def: false },\n { n: 'source', t: 'text_sm' },\n { n: 'created_at', t: 'ts', def: '$now' },\n { n: 'updated_at', t: 'ts', def: '$now', mysqlUpd: true },\n ],\n uq: [{ cols: ['visitor_id', 'profile_id'] }],\n}\n\n// Full schema — includes enterprise columns; used for PostgreSQL/MySQL\nconst consentRecordsFull: TableDef = {\n name: 'consent_records',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants' },\n { n: 'visitor_id', t: 'text' },\n { n: 'profile_id', t: 'text', ref: 'profiles' },\n { n: 'profile_version', t: 'int' },\n { n: 'locale', t: 'text_sm' },\n { n: 'consent_json', t: 'json' },\n { n: 'gpc_detected', t: 'bool', def: false },\n { n: 'source', t: 'text_sm' },\n { n: 'age_verified', t: 'bool', def: false },\n { n: 'parental_consent_token', t: 'longtext', null: true },\n { n: 'tcf_string', t: 'longtext', null: true },\n { n: 'created_at', t: 'ts', def: '$now' },\n { n: 'updated_at', t: 'ts', def: '$now', mysqlUpd: true },\n ],\n uq: [{ cols: ['visitor_id', 'profile_id'] }],\n}\n\nconst consentHistory: TableDef = {\n name: 'consent_history',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants' },\n { n: 'consent_record_id', t: 'text', ref: 'consent_records' },\n { n: 'visitor_id', t: 'text' },\n { n: 'old_json', t: 'json', null: true },\n { n: 'new_json', t: 'json' },\n { n: 'action', t: 'text_sm' },\n { n: 'created_at', t: 'ts', def: '$now' },\n ],\n}\n\nconst visitors: TableDef = {\n name: 'visitors',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants' },\n { n: 'visitor_id', t: 'text', unique: true },\n { n: 'country', t: 'text_geo', null: true },\n { n: 'region', t: 'text_md', null: true },\n { n: 'city', t: 'text_md', null: true },\n { n: 'ip_hash', t: 'text_hash', null: true },\n { n: 'user_agent_hash', t: 'text_hash', null: true },\n { n: 'first_seen', t: 'ts', def: '$now' },\n { n: 'last_seen', t: 'ts', def: '$now', mysqlUpd: true },\n ],\n}\n\n// SQLite initial schema — without TOTP columns (added via ALTER TABLE in v3 migration)\nconst usersBase: TableDef = {\n name: 'users',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants' },\n { n: 'name', t: 'text' },\n { n: 'email', t: 'text', unique: true },\n { n: 'password_hash', t: 'text' },\n { n: 'is_active', t: 'bool', def: true },\n { n: 'created_at', t: 'ts', def: '$now' },\n { n: 'updated_at', t: 'ts', def: '$now', mysqlUpd: true },\n ],\n}\n\n// Full schema — includes TOTP columns; used for PostgreSQL/MySQL\nconst usersFull: TableDef = {\n name: 'users',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants' },\n { n: 'name', t: 'text' },\n { n: 'email', t: 'text', unique: true },\n { n: 'password_hash', t: 'text' },\n { n: 'is_active', t: 'bool', def: true },\n { n: 'totp_secret', t: 'longtext', null: true },\n { n: 'totp_enabled', t: 'bool', def: false },\n { n: 'created_at', t: 'ts', def: '$now' },\n { n: 'updated_at', t: 'ts', def: '$now', mysqlUpd: true },\n ],\n}\n\nconst roles: TableDef = {\n name: 'roles',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants' },\n { n: 'name', t: 'text_md' },\n { n: 'description', t: 'text', null: true },\n ],\n}\n\nconst permissions: TableDef = {\n name: 'permissions',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'name', t: 'text_md', unique: true },\n { n: 'description', t: 'text', null: true },\n ],\n}\n\n// SQLite v1 — no tenant_id column (added via ALTER TABLE in v4 migration)\nconst userRolesBase: TableDef = {\n name: 'user_roles',\n cols: [\n { n: 'user_id', t: 'text', ref: 'users' },\n { n: 'role_id', t: 'text', ref: 'roles' },\n ],\n pk: ['user_id', 'role_id'],\n}\n\n// Full schema with tenant_id — used for PostgreSQL/MySQL\nconst userRolesFull: TableDef = {\n name: 'user_roles',\n cols: [\n { n: 'user_id', t: 'text', ref: 'users' },\n { n: 'role_id', t: 'text', ref: 'roles' },\n { n: 'tenant_id', t: 'text', def: 'default' },\n ],\n pk: ['user_id', 'role_id', 'tenant_id'],\n}\n\nconst rolePermissions: TableDef = {\n name: 'role_permissions',\n cols: [\n { n: 'role_id', t: 'text', ref: 'roles' },\n { n: 'permission_id', t: 'text', ref: 'permissions' },\n ],\n pk: ['role_id', 'permission_id'],\n}\n\nconst auditLogs: TableDef = {\n name: 'audit_logs',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants' },\n { n: 'user_id', t: 'text', null: true },\n { n: 'action', t: 'text_md' },\n { n: 'resource_type', t: 'text_md' },\n { n: 'resource_id', t: 'text', null: true },\n { n: 'old_data', t: 'json', null: true },\n { n: 'new_data', t: 'json', null: true },\n { n: 'created_at', t: 'ts', def: '$now' },\n ],\n}\n\nconst apiKeys: TableDef = {\n name: 'api_keys',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants', onDel: 'CASCADE' },\n { n: 'key_hash', t: 'text_hash', unique: true },\n { n: 'name', t: 'text' },\n { n: 'is_active', t: 'bool', def: true },\n { n: 'created_at', t: 'ts', def: '$now' },\n ],\n}\n\nconst cookieTemplates: TableDef = {\n name: 'cookie_templates',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants', onDel: 'CASCADE' },\n { n: 'name', t: 'text' },\n { n: 'cookies_json', t: 'json', def: '$arr' },\n { n: 'created_at', t: 'ts', def: '$now' },\n { n: 'updated_at', t: 'ts', def: '$now', mysqlUpd: true },\n ],\n}\n\nconst uiTemplates: TableDef = {\n name: 'ui_templates',\n cols: [\n { n: 'id', t: 'pk' },\n { n: 'tenant_id', t: 'text', ref: 'tenants', onDel: 'CASCADE' },\n { n: 'name', t: 'text' },\n { n: 'settings_json', t: 'json', def: '$obj' },\n { n: 'created_at', t: 'ts', def: '$now' },\n { n: 'updated_at', t: 'ts', def: '$now', mysqlUpd: true },\n ],\n}\n\n// ── Exported table definition groups ─────────────────────────────────────────\n\n/** Core tables for SQLite initial (v1) migration — no enterprise columns, no tenant_id in user_roles. */\nexport const CORE_TABLES_SQLITE: readonly TableDef[] = [\n tenants, profiles, consentRecordsBase, consentHistory, visitors,\n usersBase, roles, permissions, userRolesBase, rolePermissions, auditLogs,\n]\n\n/** Core tables with all current columns — for PostgreSQL/MySQL full initial schema. */\nexport const CORE_TABLES_FULL: readonly TableDef[] = [\n tenants, profiles, consentRecordsFull, consentHistory, visitors,\n usersFull, roles, permissions, userRolesFull, rolePermissions, auditLogs,\n]\n\n/** api_keys table — SQLite v2 migration. */\nexport const API_KEY_TABLES: readonly TableDef[] = [apiKeys]\n\n/** Template tables — SQLite v5 migration. */\nexport const TEMPLATE_TABLES: readonly TableDef[] = [cookieTemplates, uiTemplates]\n\n// ── SQL generators ────────────────────────────────────────────────────────────\n\nfunction sqliteDef(def: string | number | boolean): string {\n if (def === '$now') return `DEFAULT (datetime('now'))`\n if (def === '$arr') return `DEFAULT '[]'`\n if (def === '$obj') return `DEFAULT '{}'`\n if (def === true) return 'DEFAULT 1'\n if (def === false) return 'DEFAULT 0'\n if (typeof def === 'string') return `DEFAULT '${def}'`\n return `DEFAULT ${def}`\n}\n\nfunction buildColSQLite(c: ColDef): string {\n if (c.t === 'pk') return `${c.n} TEXT PRIMARY KEY`\n const type = (c.t === 'int' || c.t === 'bool') ? 'INTEGER' : 'TEXT'\n const parts = [`${c.n} ${type}`]\n if (!c.null) parts.push('NOT NULL')\n if (c.def !== undefined) parts.push(sqliteDef(c.def))\n if (c.unique) parts.push('UNIQUE')\n if (c.ref) { parts.push(`REFERENCES ${c.ref}(id)`); if (c.onDel) parts.push(`ON DELETE ${c.onDel}`) }\n return parts.join(' ')\n}\n\nfunction buildTableSQLite(t: TableDef): string {\n const lines = t.cols.map(c => ` ${buildColSQLite(c)}`)\n if (t.pk) lines.push(` PRIMARY KEY (${t.pk.join(', ')})`)\n if (t.uq) for (const u of t.uq) lines.push(` UNIQUE(${u.cols.join(', ')})`)\n return `CREATE TABLE IF NOT EXISTS ${t.name} (\\n${lines.join(',\\n')}\\n);`\n}\n\nfunction pgDef(def: string | number | boolean): string {\n if (def === '$now') return 'DEFAULT NOW()'\n if (def === '$arr') return `DEFAULT '[]'`\n if (def === '$obj') return `DEFAULT '{}'`\n if (def === true) return 'DEFAULT TRUE'\n if (def === false) return 'DEFAULT FALSE'\n if (typeof def === 'string') return `DEFAULT '${def}'`\n return `DEFAULT ${def}`\n}\n\nfunction buildColPg(c: ColDef): string {\n if (c.t === 'pk') return `${c.n} TEXT PRIMARY KEY`\n const type = c.t === 'json' ? 'JSONB' : c.t === 'int' ? 'INTEGER' : c.t === 'bool' ? 'BOOLEAN' : c.t === 'ts' ? 'TIMESTAMPTZ' : 'TEXT'\n const parts = [`${c.n} ${type}`]\n if (!c.null) parts.push('NOT NULL')\n if (c.def !== undefined) parts.push(pgDef(c.def))\n if (c.unique) parts.push('UNIQUE')\n if (c.ref) { parts.push(`REFERENCES ${c.ref}(id)`); if (c.onDel) parts.push(`ON DELETE ${c.onDel}`) }\n return parts.join(' ')\n}\n\nfunction buildTablePg(t: TableDef): string {\n const lines = t.cols.map(c => ` ${buildColPg(c)}`)\n if (t.pk) lines.push(` PRIMARY KEY (${t.pk.join(', ')})`)\n if (t.uq) for (const u of t.uq) lines.push(` UNIQUE (${u.cols.join(', ')})`)\n return `CREATE TABLE IF NOT EXISTS ${t.name} (\\n${lines.join(',\\n')}\\n);`\n}\n\nconst MYSQL_TEXT: Partial<Record<ColType, string>> = {\n text: 'VARCHAR(255)', text_sm: 'VARCHAR(20)', text_md: 'VARCHAR(100)',\n text_geo: 'VARCHAR(10)', text_hash: 'VARCHAR(64)', longtext: 'LONGTEXT', json: 'LONGTEXT',\n}\n\nfunction mysqlDef(def: string | number | boolean): string {\n if (def === '$now') return 'DEFAULT CURRENT_TIMESTAMP'\n if (def === '$arr') return `DEFAULT '[]'`\n if (def === '$obj') return `DEFAULT '{}'`\n if (def === true) return 'DEFAULT 1'\n if (def === false) return 'DEFAULT 0'\n if (typeof def === 'string') return `DEFAULT '${def}'`\n return `DEFAULT ${def}`\n}\n\nfunction buildColMySQL(c: ColDef): string {\n if (c.t === 'pk') return `${c.n} VARCHAR(36) PRIMARY KEY`\n const type = c.t === 'int' ? 'INT' : c.t === 'bool' ? 'TINYINT(1)' : c.t === 'ts' ? 'DATETIME' : (MYSQL_TEXT[c.t] ?? 'TEXT')\n const parts = [`${c.n} ${type}`]\n if (!c.null) parts.push('NOT NULL')\n if (c.def !== undefined) parts.push(mysqlDef(c.def))\n if (c.mysqlUpd) parts.push('ON UPDATE CURRENT_TIMESTAMP')\n if (c.unique) parts.push('UNIQUE')\n if (c.ref) { parts.push(`REFERENCES ${c.ref}(id)`); if (c.onDel) parts.push(`ON DELETE ${c.onDel}`) }\n return parts.join(' ')\n}\n\nfunction buildTableMySQL(t: TableDef): string {\n const lines = t.cols.map(c => ` ${buildColMySQL(c)}`)\n if (t.pk) lines.push(` PRIMARY KEY (${t.pk.join(', ')})`)\n if (t.uq) for (const u of t.uq) lines.push(` UNIQUE KEY uq_${u.cols.join('_')} (${u.cols.join(', ')})`)\n return `CREATE TABLE IF NOT EXISTS ${t.name} (\\n${lines.join(',\\n')}\\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;`\n}\n\nfunction toSQLite(tables: readonly TableDef[]): string { return tables.map(buildTableSQLite).join('\\n') }\nfunction toPostgres(tables: readonly TableDef[]): string { return tables.map(buildTablePg).join('\\n') }\nfunction toMySQL(tables: readonly TableDef[]): string { return tables.map(buildTableMySQL).join('\\n') }\n\n// ── Schema SQL exports ────────────────────────────────────────────────────────\n// SQLite: separate blocks matching its versioned migration steps.\n// PostgreSQL/MySQL: one block containing the full current schema.\n\n/** SQLite v1 migration: core tables. */\nexport const SCHEMA_SQL_SQLITE = toSQLite(CORE_TABLES_SQLITE)\n\n/** SQLite v2 migration: api_keys table. */\nexport const SCHEMA_SQL_SQLITE_API_KEYS = toSQLite(API_KEY_TABLES)\n\n/** SQLite v3 migration: enterprise columns added via ALTER TABLE (not generatable from TableDef). */\nexport const SCHEMA_SQL_SQLITE_ENTERPRISE = `\nALTER TABLE consent_records ADD COLUMN age_verified INTEGER NOT NULL DEFAULT 0;\nALTER TABLE consent_records ADD COLUMN parental_consent_token TEXT;\nALTER TABLE consent_records ADD COLUMN tcf_string TEXT;\nALTER TABLE users ADD COLUMN totp_secret TEXT;\nALTER TABLE users ADD COLUMN totp_enabled INTEGER NOT NULL DEFAULT 0;\n`\n\n/** SQLite v5 migration: template tables. */\nexport const SCHEMA_SQL_SQLITE_TEMPLATES = toSQLite(TEMPLATE_TABLES)\n\nconst ALL_TABLES_FULL: readonly TableDef[] = [...CORE_TABLES_FULL, ...API_KEY_TABLES, ...TEMPLATE_TABLES]\n\n/** PostgreSQL full schema — all tables with current column set. */\nexport const SCHEMA_SQL_POSTGRES =\n toPostgres(ALL_TABLES_FULL) +\n '\\nCREATE TABLE IF NOT EXISTS schema_version (version INTEGER PRIMARY KEY);\\n'\n\n/** MySQL full schema — all tables with current column set. */\nexport const SCHEMA_SQL_MYSQL =\n toMySQL(ALL_TABLES_FULL) +\n '\\nCREATE TABLE IF NOT EXISTS schema_version (\\n version INT NOT NULL PRIMARY KEY\\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\\n'\n\n// ── Core data ─────────────────────────────────────────────────────────────────\n\nexport interface SeedPermission { id: string; name: string; description: string }\nexport interface SeedRole { id: string; tenantId: string; name: string; description: string }\nexport interface SeedRolePermission { roleId: string; permissionId: string }\n\nexport const SEED_TENANT = { id: 'default', name: 'Default', slug: 'default' } as const\n\nexport const SEED_PERMISSIONS: SeedPermission[] = [\n { id: 'perm_profile_create', name: 'profile:create', description: 'Create profiles' },\n { id: 'perm_profile_update', name: 'profile:update', description: 'Update profiles' },\n { id: 'perm_profile_delete', name: 'profile:delete', description: 'Delete profiles' },\n { id: 'perm_profile_view', name: 'profile:view', description: 'View profiles' },\n { id: 'perm_consent_view', name: 'consent:view', description: 'View consent records' },\n { id: 'perm_visitor_view', name: 'visitor:view', description: 'View visitor records' },\n { id: 'perm_user_create', name: 'user:create', description: 'Create users' },\n { id: 'perm_user_update', name: 'user:update', description: 'Update users' },\n { id: 'perm_user_delete', name: 'user:delete', description: 'Delete users' },\n { id: 'perm_user_view', name: 'user:view', description: 'View users' },\n { id: 'perm_role_create', name: 'role:create', description: 'Create roles' },\n { id: 'perm_role_update', name: 'role:update', description: 'Update roles' },\n { id: 'perm_role_delete', name: 'role:delete', description: 'Delete roles' },\n { id: 'perm_role_view', name: 'role:view', description: 'View roles' },\n { id: 'perm_audit_view', name: 'audit:view', description: 'View audit logs' },\n { id: 'perm_settings_update', name: 'settings:update', description: 'Update settings' },\n { id: 'perm_export_run', name: 'export:run', description: 'Run data exports' },\n]\n\nexport const SEED_ROLES: SeedRole[] = [\n { id: 'role_super_admin', tenantId: 'default', name: 'super_admin', description: 'Full system access' },\n { id: 'role_admin', tenantId: 'default', name: 'admin', description: 'Administrative access' },\n { id: 'role_compliance_officer', tenantId: 'default', name: 'compliance_officer', description: 'Compliance read access' },\n { id: 'role_viewer', tenantId: 'default', name: 'viewer', description: 'Read-only access' },\n]\n\nconst adminExcluded = new Set(['role:delete', 'user:delete'])\nconst complianceAllowed = new Set(['consent:view', 'visitor:view', 'audit:view', 'profile:view', 'export:run'])\nconst viewerAllowed = new Set(['consent:view', 'visitor:view', 'profile:view'])\n\nexport const SEED_ROLE_PERMISSIONS: SeedRolePermission[] = [\n ...SEED_PERMISSIONS.map(p => ({ roleId: 'role_super_admin', permissionId: p.id })),\n ...SEED_PERMISSIONS.filter(p => !adminExcluded.has(p.name)).map(p => ({ roleId: 'role_admin', permissionId: p.id })),\n ...SEED_PERMISSIONS.filter(p => complianceAllowed.has(p.name)).map(p => ({ roleId: 'role_compliance_officer', permissionId: p.id })),\n ...SEED_PERMISSIONS.filter(p => viewerAllowed.has(p.name)).map(p => ({ roleId: 'role_viewer', permissionId: p.id })),\n]\n\n// ── SQLite seed SQL ───────────────────────────────────────────────────────────\n// Generated from seed data above — idempotent via INSERT OR IGNORE.\n// MongoDB, MySQL, PostgreSQL adapters use the typed JS objects directly.\n\nfunction q(s: string): string { return `'${s.replace(/'/g, \"''\")}'` }\n\nfunction generateSeedSQL(): string {\n const { id, name, slug } = SEED_TENANT\n const tenant = `INSERT OR IGNORE INTO tenants (id, name, slug) VALUES (${q(id)},${q(name)},${q(slug)});`\n\n const perms = `INSERT OR IGNORE INTO permissions (id, name, description) VALUES\\n${\n SEED_PERMISSIONS.map(p => ` (${q(p.id)},${q(p.name)},${q(p.description)})`).join(',\\n')\n };`\n\n const rolesSQL = `INSERT OR IGNORE INTO roles (id, tenant_id, name, description) VALUES\\n${\n SEED_ROLES.map(r => ` (${q(r.id)},${q(r.tenantId)},${q(r.name)},${q(r.description)})`).join(',\\n')\n };`\n\n const byRole = new Map<string, string[]>()\n for (const rp of SEED_ROLE_PERMISSIONS) {\n if (!byRole.has(rp.roleId)) byRole.set(rp.roleId, [])\n byRole.get(rp.roleId)!.push(rp.permissionId)\n }\n const rolePerms = [...byRole.entries()].map(([roleId, permIds]) =>\n `INSERT OR IGNORE INTO role_permissions (role_id, permission_id) VALUES\\n${\n permIds.map(pid => ` (${q(roleId)},${q(pid)})`).join(',\\n')\n };`\n ).join('\\n')\n\n return [tenant, perms, rolesSQL, rolePerms].join('\\n')\n}\n\nexport const SEED_SQL = generateSeedSQL()\n","import type { Database as DB, Statement } from 'better-sqlite3'\n\nconst MAX_PAGE_SIZE = 500\nimport { randomUUID, randomProfileId } from '../../utils/crypto'\nimport { resolveStoragePaths } from '../../utils/storage-path'\nimport {\n SEED_SQL,\n SCHEMA_SQL_SQLITE,\n SCHEMA_SQL_SQLITE_API_KEYS,\n SCHEMA_SQL_SQLITE_ENTERPRISE,\n SCHEMA_SQL_SQLITE_TEMPLATES,\n} from '../seed-data'\nimport type {\n StorageAdapter,\n StorageConfig,\n Profile,\n ProfileConfig,\n CreateProfileInput,\n UpdateProfileInput,\n ConsentDbRecord,\n ConsentHistoryEntry,\n ConsentValue,\n CreateConsentInput,\n UpdateConsentInput,\n ConsentFilters,\n Visitor,\n VisitorFilters,\n CreateVisitorInput,\n UpdateVisitorInput,\n AdminUser,\n CreateUserInput,\n UpdateUserInput,\n Role,\n CreateRoleInput,\n UpdateRoleInput,\n Permission,\n AuditLog,\n AuditFilters,\n CreateAuditLogInput,\n OverviewStats,\n CategoryStats,\n TimelineEntry,\n CountryStat,\n GpcStats,\n Tenant,\n ApiKey,\n CreateApiKeyInput,\n CreateTenantInput,\n UpdateTenantInput,\n ServerCookieTemplate,\n ServerUITemplate,\n CreateCookieTemplateInput,\n UpdateCookieTemplateInput,\n CreateUITemplateInput,\n UpdateUITemplateInput,\n ProfileSummary,\n OptInStats,\n OptInFilters,\n ComplianceGroupId,\n} from '@consenti/types'\n\ninterface RawProfile {\n id: string; tenant_id: string; name: string; default_locale: string\n version: number; profile_json: string\n created_at: string; updated_at: string\n}\ninterface RawConsent {\n id: string; tenant_id: string; visitor_id: string; profile_id: string\n profile_version: number; locale: string; consent_json: string\n gpc_detected: number; source: string; created_at: string; updated_at: string\n age_verified?: number; parental_consent_token?: string | null; tcf_string?: string | null\n}\ninterface RawConsentHistory {\n id: string; tenant_id: string; consent_record_id: string; visitor_id: string\n old_json: string | null; new_json: string; action: string; created_at: string\n}\ninterface RawVisitor {\n id: string; tenant_id: string; visitor_id: string\n country: string | null; region: string | null; city: string | null\n ip_hash: string | null; user_agent_hash: string | null\n first_seen: string; last_seen: string\n}\ninterface RawUser {\n id: string; tenant_id: string; name: string; email: string\n password_hash: string; is_active: number; created_at: string; updated_at: string\n totp_secret?: string | null; totp_enabled?: number\n allowed_tenants?: string | null\n}\ninterface RawProfileSummary {\n id: string; name: string; default_locale: string; version: number\n compliance_group: string | null; is_active: number\n cookie_template_name: string | null; ui_template_name: string | null\n created_at: string; updated_at: string\n cookie_template_id: string | null; ui_template_id: string | null\n}\ninterface RawRole {\n id: string; tenant_id: string; name: string; description: string | null\n}\ninterface RawPermission {\n id: string; name: string; description: string | null\n}\ninterface RawAuditLog {\n id: string; tenant_id: string; user_id: string | null; action: string\n resource_type: string; resource_id: string | null\n old_data: string | null; new_data: string | null; created_at: string\n}\ninterface RawTenant {\n id: string; name: string; slug: string; created_at: string; updated_at: string\n}\ninterface RawApiKey {\n id: string; tenant_id: string; key_hash: string; name: string; is_active: number; created_at: string\n}\n\ninterface RawCookieTemplate {\n id: string; tenant_id: string; name: string; cookies_json: string; created_at: string; updated_at: string\n}\ninterface RawUITemplate {\n id: string; tenant_id: string; name: string; settings_json: string; created_at: string; updated_at: string\n}\n\n\ntype Stmt = Statement\n\nexport class BetterSqlite3Adapter implements StorageAdapter {\n private db!: DB\n private cache = new Map<string, Stmt>()\n\n constructor(private config: StorageConfig) {}\n\n private stmt(sql: string): Stmt {\n let s = this.cache.get(sql)\n if (!s) { s = this.db.prepare(sql); this.cache.set(sql, s) }\n return s\n }\n\n async connect(): Promise<void> {\n // Lazy: only loaded when this driver is selected — keeps better-sqlite3\n // as an optional peer dep without crashing startup for other drivers.\n const mod = await import('better-sqlite3').catch(() => {\n throw new Error(\"driver 'better-sqlite3' requires: npm install better-sqlite3\")\n }) as { default: new(path: string) => DB }\n const { dbPath } = resolveStoragePaths(this.config.path ?? './consenti-data', 'better-sqlite3')\n this.db = new mod.default(dbPath)\n this.db.exec('PRAGMA journal_mode=WAL')\n this.db.exec('PRAGMA foreign_keys=ON')\n this.db.exec('PRAGMA synchronous=NORMAL')\n await this.migrate()\n }\n\n async disconnect(): Promise<void> {\n this.cache.clear()\n this.db.close()\n }\n\n async migrate(): Promise<void> {\n const row = this.db.prepare('PRAGMA user_version').get() as { user_version: number }\n if (row.user_version < 1) {\n this.db.exec(SCHEMA_SQL_SQLITE)\n this.db.exec(SEED_SQL)\n this.db.exec('PRAGMA user_version = 1')\n }\n if (row.user_version < 2) {\n this.db.exec(SCHEMA_SQL_SQLITE_API_KEYS)\n this.db.exec('PRAGMA user_version = 2')\n }\n if (row.user_version < 3) {\n this.db.exec(SCHEMA_SQL_SQLITE_ENTERPRISE)\n this.db.exec('PRAGMA user_version = 3')\n }\n if (row.user_version < 4) {\n this.db.exec('ALTER TABLE user_roles ADD COLUMN tenant_id TEXT NOT NULL DEFAULT \\'default\\'')\n this.db.exec('PRAGMA user_version = 4')\n }\n if (row.user_version < 5) {\n this.db.exec(SCHEMA_SQL_SQLITE_TEMPLATES)\n this.db.exec('PRAGMA user_version = 5')\n }\n if (row.user_version < 6) {\n this.db.exec('ALTER TABLE users ADD COLUMN allowed_tenants TEXT')\n this.db.exec('PRAGMA user_version = 6')\n }\n\n this.db.exec(`\n CREATE INDEX IF NOT EXISTS idx_profiles_tenant_compliance_active\n ON profiles (tenant_id, json_extract(profile_json,'$.complianceGroup'), json_extract(profile_json,'$.isActive'));\n CREATE INDEX IF NOT EXISTS idx_profiles_tenant\n ON profiles (tenant_id);\n CREATE INDEX IF NOT EXISTS idx_consents_tenant_profile_date\n ON consent_records (tenant_id, profile_id, created_at);\n CREATE INDEX IF NOT EXISTS idx_consents_visitor\n ON consent_records (visitor_id);\n CREATE INDEX IF NOT EXISTS idx_visitors_tenant\n ON visitors (tenant_id);\n CREATE INDEX IF NOT EXISTS idx_audit_tenant_date\n ON audit_logs (tenant_id, created_at);\n `)\n }\n\n // ── Profiles ──────────────────────────────────────────────────────────────\n\n private mapProfile(row: RawProfile): Profile {\n return {\n id: row.id,\n tenantId: row.tenant_id,\n name: row.name,\n defaultLocale: row.default_locale,\n version: row.version,\n profileJson: JSON.parse(row.profile_json) as ProfileConfig,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }\n }\n\n async createProfile(data: CreateProfileInput): Promise<Profile> {\n const id = randomProfileId()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO profiles (id,tenant_id,name,default_locale,profile_json,created_at,updated_at) VALUES (?,?,?,?,?,?,?)'\n ).run(id, data.tenantId, data.name, data.defaultLocale, JSON.stringify(data.profileJson), now, now)\n const profile = await this.getProfile(id)\n if (!profile) throw new Error('Failed to create profile')\n return profile\n }\n\n async updateProfile(id: string, data: UpdateProfileInput): Promise<Profile> {\n const existing = await this.getProfile(id)\n if (!existing) throw new Error(`Profile ${id} not found`)\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?', 'version = version + 1']\n const vals: (string | number | null)[] = [now]\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.defaultLocale != null) { fields.push('default_locale = ?'); vals.push(data.defaultLocale) }\n if (data.profileJson != null) { fields.push('profile_json = ?'); vals.push(JSON.stringify(data.profileJson)) }\n vals.push(id)\n this.stmt(`UPDATE profiles SET ${fields.join(', ')} WHERE id = ?`).run(...vals)\n const updated = await this.getProfile(id)\n if (!updated) throw new Error('Failed to update profile')\n return updated\n }\n\n async deleteProfile(id: string): Promise<void> {\n this.stmt('DELETE FROM profiles WHERE id = ?').run(id)\n }\n\n async getProfile(id: string): Promise<Profile | null> {\n const row = this.stmt('SELECT * FROM profiles WHERE id = ?').get(id) as RawProfile | undefined\n return row ? this.mapProfile(row) : null\n }\n\n async getProfiles(tenantId: string): Promise<Profile[]> {\n const rows = this.stmt('SELECT * FROM profiles WHERE tenant_id = ? ORDER BY created_at ASC').all(tenantId) as unknown as RawProfile[]\n return rows.map(r => this.mapProfile(r))\n }\n\n async findActiveProfileByComplianceGroup(tenantId: string, complianceGroup: string): Promise<Profile | null> {\n const row = this.stmt(\n `SELECT * FROM profiles WHERE tenant_id = ? AND json_extract(profile_json, '$.complianceGroup') = ? AND json_extract(profile_json, '$.isActive') = 1 LIMIT 1`\n ).get(tenantId, complianceGroup) as RawProfile | undefined\n return row ? this.mapProfile(row) : null\n }\n\n // ── Consents ──────────────────────────────────────────────────────────────\n\n private mapConsent(row: RawConsent): ConsentDbRecord {\n return {\n id: row.id,\n tenantId: row.tenant_id,\n visitorId: row.visitor_id,\n profileId: row.profile_id,\n profileVersion: row.profile_version,\n locale: row.locale,\n consentJson: JSON.parse(row.consent_json) as ConsentValue,\n gpcDetected: row.gpc_detected === 1,\n source: row.source as ConsentDbRecord['source'],\n ...(row.age_verified != null && row.age_verified !== 0 ? { ageVerified: true } : {}),\n ...(row.parental_consent_token != null ? { parentalConsentToken: row.parental_consent_token } : {}),\n ...(row.tcf_string != null ? { tcfString: row.tcf_string } : {}),\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }\n }\n\n async createConsent(data: CreateConsentInput): Promise<ConsentDbRecord> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO consent_records (id,tenant_id,visitor_id,profile_id,profile_version,locale,consent_json,gpc_detected,source,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)'\n ).run(id, data.tenantId, data.visitorId, data.profileId, data.profileVersion, data.locale, JSON.stringify(data.consentJson), data.gpcDetected ? 1 : 0, data.source, now, now)\n const histId = randomUUID()\n this.stmt(\n 'INSERT INTO consent_history (id,tenant_id,consent_record_id,visitor_id,old_json,new_json,action,created_at) VALUES (?,?,?,?,?,?,?,?)'\n ).run(histId, data.tenantId, id, data.visitorId, null, JSON.stringify(data.consentJson), 'created', now)\n const record = await this.getConsent(data.visitorId)\n if (!record) throw new Error('Failed to create consent')\n return record\n }\n\n async updateConsent(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord> {\n const existing = await this.getConsent(visitorId)\n if (!existing) throw new Error(`Consent for visitor ${visitorId} not found`)\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?', 'consent_json = ?']\n const vals: (string | number | null)[] = [now, JSON.stringify(data.consentJson)]\n if (data.locale != null) { fields.push('locale = ?'); vals.push(data.locale) }\n if (data.gpcDetected != null) { fields.push('gpc_detected = ?'); vals.push(data.gpcDetected ? 1 : 0) }\n vals.push(visitorId)\n this.stmt(`UPDATE consent_records SET ${fields.join(', ')} WHERE visitor_id = ?`).run(...vals)\n const histId = randomUUID()\n this.stmt(\n 'INSERT INTO consent_history (id,tenant_id,consent_record_id,visitor_id,old_json,new_json,action,created_at) VALUES (?,?,?,?,?,?,?,?)'\n ).run(histId, existing.tenantId, existing.id, visitorId, JSON.stringify(existing.consentJson), JSON.stringify(data.consentJson), 'updated', now)\n const updated = await this.getConsent(visitorId)\n if (!updated) throw new Error('Failed to update consent')\n return updated\n }\n\n async deleteConsent(visitorId: string): Promise<void> {\n this.stmt('DELETE FROM consent_history WHERE visitor_id = ?').run(visitorId)\n this.stmt('DELETE FROM consent_records WHERE visitor_id = ?').run(visitorId)\n }\n\n async getConsent(visitorId: string): Promise<ConsentDbRecord | null> {\n const row = this.stmt('SELECT * FROM consent_records WHERE visitor_id = ?').get(visitorId) as RawConsent | undefined\n return row ? this.mapConsent(row) : null\n }\n\n async getConsents(filters: ConsentFilters): Promise<ConsentDbRecord[]> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: (string | number | null)[] = [filters.tenantId]\n if (filters.profileId) { conditions.push('profile_id = ?'); vals.push(filters.profileId) }\n if (filters.from) { conditions.push('created_at >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('created_at <= ?'); vals.push(filters.to) }\n const limit = Math.min(filters.limit ?? 50, MAX_PAGE_SIZE)\n const offset = ((filters.page ?? 1) - 1) * limit\n vals.push(limit, offset)\n const rows = this.stmt(\n `SELECT * FROM consent_records WHERE ${conditions.join(' AND ')} ORDER BY created_at DESC LIMIT ? OFFSET ?`\n ).all(...vals) as unknown as RawConsent[]\n return rows.map(r => this.mapConsent(r))\n }\n\n async *streamConsents(filters: ConsentFilters): AsyncIterable<ConsentDbRecord> {\n const pageSize = 500\n let offset = 0\n while (true) {\n const rows = this.stmt(\n 'SELECT * FROM consent_records WHERE tenant_id = ? LIMIT ? OFFSET ?'\n ).all(filters.tenantId, pageSize, offset) as unknown as RawConsent[]\n if (rows.length === 0) break\n for (const row of rows) yield this.mapConsent(row)\n offset += pageSize\n }\n }\n\n async getConsentHistory(visitorId: string): Promise<ConsentHistoryEntry[]> {\n const rows = this.stmt(\n 'SELECT * FROM consent_history WHERE visitor_id = ? ORDER BY created_at ASC'\n ).all(visitorId) as unknown as RawConsentHistory[]\n return rows.map(r => ({\n id: r.id,\n tenantId: r.tenant_id,\n consentRecordId: r.consent_record_id,\n visitorId: r.visitor_id,\n oldJson: r.old_json != null ? JSON.parse(r.old_json) as ConsentValue : null,\n newJson: JSON.parse(r.new_json) as ConsentValue,\n action: r.action as ConsentHistoryEntry['action'],\n createdAt: r.created_at,\n }))\n }\n\n // ── Visitors ──────────────────────────────────────────────────────────────\n\n private mapVisitor(row: RawVisitor): Visitor {\n return {\n id: row.id,\n tenantId: row.tenant_id,\n visitorId: row.visitor_id,\n firstSeen: row.first_seen,\n lastSeen: row.last_seen,\n ...(row.country != null ? { country: row.country } : {}),\n ...(row.region != null ? { region: row.region } : {}),\n ...(row.city != null ? { city: row.city } : {}),\n ...(row.ip_hash != null ? { ipHash: row.ip_hash } : {}),\n ...(row.user_agent_hash != null ? { userAgentHash: row.user_agent_hash } : {}),\n }\n }\n\n async createVisitor(data: CreateVisitorInput): Promise<Visitor> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO visitors (id,tenant_id,visitor_id,country,region,city,ip_hash,user_agent_hash,first_seen,last_seen) VALUES (?,?,?,?,?,?,?,?,?,?)'\n ).run(id, data.tenantId, data.visitorId, data.country ?? null, data.region ?? null, data.city ?? null, data.ipHash ?? null, data.userAgentHash ?? null, now, now)\n const visitor = await this.getVisitor(data.visitorId)\n if (!visitor) throw new Error('Failed to create visitor')\n return visitor\n }\n\n async updateVisitor(visitorId: string, data: UpdateVisitorInput): Promise<Visitor> {\n const now = new Date().toISOString()\n const fields: string[] = ['last_seen = ?']\n const vals: (string | number | null)[] = [data.lastSeen ?? now]\n if (data.country != null) { fields.push('country = ?'); vals.push(data.country) }\n if (data.region != null) { fields.push('region = ?'); vals.push(data.region) }\n if (data.city != null) { fields.push('city = ?'); vals.push(data.city) }\n vals.push(visitorId)\n this.stmt(`UPDATE visitors SET ${fields.join(', ')} WHERE visitor_id = ?`).run(...vals)\n const visitor = await this.getVisitor(visitorId)\n if (!visitor) throw new Error(`Visitor ${visitorId} not found`)\n return visitor\n }\n\n async deleteVisitor(visitorId: string): Promise<void> {\n this.stmt('DELETE FROM visitors WHERE visitor_id = ?').run(visitorId)\n }\n\n async getVisitor(visitorId: string): Promise<Visitor | null> {\n const row = this.stmt('SELECT * FROM visitors WHERE visitor_id = ?').get(visitorId) as RawVisitor | undefined\n return row ? this.mapVisitor(row) : null\n }\n\n async getVisitors(filters: VisitorFilters): Promise<Visitor[]> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: (string | number | null)[] = [filters.tenantId]\n if (filters.from) { conditions.push('first_seen >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('first_seen <= ?'); vals.push(filters.to) }\n const limit = Math.min(filters.limit ?? 50, MAX_PAGE_SIZE)\n const offset = ((filters.page ?? 1) - 1) * limit\n vals.push(limit, offset)\n const rows = this.stmt(\n `SELECT * FROM visitors WHERE ${conditions.join(' AND ')} ORDER BY last_seen DESC LIMIT ? OFFSET ?`\n ).all(...vals) as unknown as RawVisitor[]\n return rows.map(r => this.mapVisitor(r))\n }\n\n // ── Users ─────────────────────────────────────────────────────────────────\n\n private mapUser(row: RawUser): AdminUser {\n const allowedTenants: string[] = row.allowed_tenants\n ? JSON.parse(row.allowed_tenants) as string[]\n : []\n return {\n id: row.id,\n tenantId: row.tenant_id,\n name: row.name,\n email: row.email,\n passwordHash: row.password_hash,\n isActive: row.is_active === 1,\n totpEnabled: row.totp_enabled === 1,\n ...(row.totp_secret != null ? { totpSecret: row.totp_secret } : {}),\n allowedTenants,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }\n }\n\n async createUser(data: CreateUserInput): Promise<AdminUser> {\n const id = randomUUID()\n const now = new Date().toISOString()\n const allowedTenantsJson = data.allowedTenants?.length ? JSON.stringify(data.allowedTenants) : null\n this.stmt(\n 'INSERT INTO users (id,tenant_id,name,email,password_hash,allowed_tenants,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?)'\n ).run(id, data.tenantId, data.name, data.email, data.passwordHash, allowedTenantsJson, now, now)\n const user = await this.getUserByEmail(data.email)\n if (!user) throw new Error('Failed to create user')\n return user\n }\n\n async updateUser(id: string, data: UpdateUserInput): Promise<AdminUser> {\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?']\n const vals: (string | number | null)[] = [now]\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.email != null) { fields.push('email = ?'); vals.push(data.email) }\n if (data.passwordHash != null) { fields.push('password_hash = ?'); vals.push(data.passwordHash) }\n if (data.isActive != null) { fields.push('is_active = ?'); vals.push(data.isActive ? 1 : 0) }\n if ('totpSecret' in data) { fields.push('totp_secret = ?'); vals.push(data.totpSecret ?? null) }\n if (data.totpEnabled != null) { fields.push('totp_enabled = ?'); vals.push(data.totpEnabled ? 1 : 0) }\n if ('allowedTenants' in data) {\n fields.push('allowed_tenants = ?')\n vals.push(data.allowedTenants?.length ? JSON.stringify(data.allowedTenants) : null)\n }\n vals.push(id)\n this.stmt(`UPDATE users SET ${fields.join(', ')} WHERE id = ?`).run(...vals)\n const row = this.stmt('SELECT * FROM users WHERE id = ?').get(id) as RawUser | undefined\n if (!row) throw new Error(`User ${id} not found`)\n return this.mapUser(row)\n }\n\n async deleteUser(id: string): Promise<void> {\n this.stmt('DELETE FROM user_roles WHERE user_id = ?').run(id)\n this.stmt('DELETE FROM users WHERE id = ?').run(id)\n }\n\n async getUserById(id: string): Promise<AdminUser | null> {\n const row = this.stmt('SELECT * FROM users WHERE id = ?').get(id) as RawUser | undefined\n return row ? this.mapUser(row) : null\n }\n\n async getUserByEmail(email: string): Promise<AdminUser | null> {\n const row = this.stmt('SELECT * FROM users WHERE email = ?').get(email) as RawUser | undefined\n return row ? this.mapUser(row) : null\n }\n\n async getUsers(tenantId: string): Promise<AdminUser[]> {\n const rows = this.stmt('SELECT * FROM users WHERE tenant_id = ? ORDER BY created_at ASC').all(tenantId) as unknown as RawUser[]\n return rows.map(r => this.mapUser(r))\n }\n\n async countUsers(tenantId?: string): Promise<number> {\n const row = tenantId\n ? this.stmt('SELECT COUNT(*) as n FROM users WHERE tenant_id = ?').get(tenantId) as { n: number } | undefined\n : this.stmt('SELECT COUNT(*) as n FROM users').get() as { n: number } | undefined\n return row?.n ?? 0\n }\n\n // ── Roles & Permissions ───────────────────────────────────────────────────\n\n async getRoles(tenantId: string): Promise<Role[]> {\n const rows = this.stmt('SELECT * FROM roles WHERE tenant_id = ?').all(tenantId) as unknown as RawRole[]\n return rows.map(r => ({\n id: r.id, tenantId: r.tenant_id, name: r.name,\n ...(r.description != null ? { description: r.description } : {}),\n }))\n }\n\n async createRole(data: CreateRoleInput): Promise<Role> {\n const id = randomUUID()\n this.stmt('INSERT INTO roles (id,tenant_id,name,description) VALUES (?,?,?,?)').run(\n id, data.tenantId, data.name, data.description ?? null\n )\n const row = this.stmt('SELECT * FROM roles WHERE id = ?').get(id) as RawRole | undefined\n if (!row) throw new Error('Failed to create role')\n return { id: row.id, tenantId: row.tenant_id, name: row.name, ...(row.description != null ? { description: row.description } : {}) }\n }\n\n async updateRole(id: string, data: UpdateRoleInput): Promise<Role> {\n const fields: string[] = []\n const vals: (string | number | null)[] = []\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.description != null) { fields.push('description = ?'); vals.push(data.description) }\n if (fields.length > 0) {\n vals.push(id)\n this.stmt(`UPDATE roles SET ${fields.join(', ')} WHERE id = ?`).run(...vals)\n }\n const row = this.stmt('SELECT * FROM roles WHERE id = ?').get(id) as RawRole | undefined\n if (!row) throw new Error(`Role ${id} not found`)\n return { id: row.id, tenantId: row.tenant_id, name: row.name, ...(row.description != null ? { description: row.description } : {}) }\n }\n\n async deleteRole(id: string): Promise<void> {\n this.stmt('DELETE FROM role_permissions WHERE role_id = ?').run(id)\n this.stmt('DELETE FROM user_roles WHERE role_id = ?').run(id)\n this.stmt('DELETE FROM roles WHERE id = ?').run(id)\n }\n\n async getAllPermissions(): Promise<Permission[]> {\n const rows = this.stmt('SELECT * FROM permissions ORDER BY name ASC').all() as unknown as RawPermission[]\n return rows.map(r => ({ id: r.id, name: r.name, ...(r.description != null ? { description: r.description } : {}) }))\n }\n\n async assignPermissionToRole(roleId: string, permissionId: string): Promise<void> {\n this.stmt('INSERT OR IGNORE INTO role_permissions (role_id,permission_id) VALUES (?,?)').run(roleId, permissionId)\n }\n\n async revokePermissionFromRole(roleId: string, permissionId: string): Promise<void> {\n this.stmt('DELETE FROM role_permissions WHERE role_id = ? AND permission_id = ?').run(roleId, permissionId)\n }\n\n async getPermissionsForRole(roleId: string): Promise<Permission[]> {\n const rows = this.stmt(\n 'SELECT p.* FROM permissions p JOIN role_permissions rp ON rp.permission_id = p.id WHERE rp.role_id = ?'\n ).all(roleId) as unknown as RawPermission[]\n return rows.map(r => ({\n id: r.id, name: r.name,\n ...(r.description != null ? { description: r.description } : {}),\n }))\n }\n\n async getUserRoles(userId: string, tenantId?: string): Promise<Role[]> {\n const rows = tenantId\n ? this.stmt(\n 'SELECT r.* FROM roles r JOIN user_roles ur ON ur.role_id = r.id WHERE ur.user_id = ? AND ur.tenant_id = ?'\n ).all(userId, tenantId) as unknown as RawRole[]\n : this.stmt(\n 'SELECT r.* FROM roles r JOIN user_roles ur ON ur.role_id = r.id WHERE ur.user_id = ?'\n ).all(userId) as unknown as RawRole[]\n return rows.map(r => ({\n id: r.id, tenantId: r.tenant_id, name: r.name,\n ...(r.description != null ? { description: r.description } : {}),\n }))\n }\n\n async assignRole(userId: string, roleId: string, tenantId = 'default'): Promise<void> {\n this.stmt('INSERT OR IGNORE INTO user_roles (user_id, role_id, tenant_id) VALUES (?,?,?)').run(userId, roleId, tenantId)\n }\n\n async revokeRole(userId: string, roleId: string, tenantId?: string): Promise<void> {\n if (tenantId) {\n this.stmt('DELETE FROM user_roles WHERE user_id = ? AND role_id = ? AND tenant_id = ?').run(userId, roleId, tenantId)\n } else {\n this.stmt('DELETE FROM user_roles WHERE user_id = ? AND role_id = ?').run(userId, roleId)\n }\n }\n\n // ── Audit ─────────────────────────────────────────────────────────────────\n\n async createLog(data: CreateAuditLogInput): Promise<void> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO audit_logs (id,tenant_id,user_id,action,resource_type,resource_id,old_data,new_data,created_at) VALUES (?,?,?,?,?,?,?,?,?)'\n ).run(\n id, data.tenantId, data.userId ?? null, data.action, data.resourceType,\n data.resourceId ?? null,\n data.oldData != null ? JSON.stringify(data.oldData) : null,\n data.newData != null ? JSON.stringify(data.newData) : null,\n now\n )\n }\n\n async getLogs(filters: AuditFilters): Promise<AuditLog[]> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: (string | number | null)[] = [filters.tenantId]\n if (filters.action) { conditions.push('action = ?'); vals.push(filters.action) }\n if (filters.resourceType) { conditions.push('resource_type = ?'); vals.push(filters.resourceType) }\n if (filters.from) { conditions.push('created_at >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('created_at <= ?'); vals.push(filters.to) }\n const limit = Math.min(filters.limit ?? 50, MAX_PAGE_SIZE)\n const offset = ((filters.page ?? 1) - 1) * limit\n vals.push(limit, offset)\n const rows = this.stmt(\n `SELECT * FROM audit_logs WHERE ${conditions.join(' AND ')} ORDER BY created_at DESC LIMIT ? OFFSET ?`\n ).all(...vals) as unknown as RawAuditLog[]\n return rows.map(r => this.mapAuditLog(r))\n }\n\n private mapAuditLog(r: RawAuditLog): AuditLog {\n return {\n id: r.id, tenantId: r.tenant_id, action: r.action,\n resourceType: r.resource_type, createdAt: r.created_at,\n ...(r.user_id != null ? { userId: r.user_id } : {}),\n ...(r.resource_id != null ? { resourceId: r.resource_id } : {}),\n ...(r.old_data != null ? { oldData: JSON.parse(r.old_data) as unknown } : {}),\n ...(r.new_data != null ? { newData: JSON.parse(r.new_data) as unknown } : {}),\n }\n }\n\n async *streamAuditLogs(filters: AuditFilters): AsyncIterable<AuditLog> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: (string | number | null)[] = [filters.tenantId]\n if (filters.action) { conditions.push('action = ?'); vals.push(filters.action) }\n if (filters.from) { conditions.push('created_at >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('created_at <= ?'); vals.push(filters.to) }\n const pageSize = 500\n let offset = 0\n while (true) {\n const rows = this.stmt(\n `SELECT * FROM audit_logs WHERE ${conditions.join(' AND ')} ORDER BY created_at DESC LIMIT ? OFFSET ?`\n ).all(...vals, pageSize, offset) as unknown as RawAuditLog[]\n if (rows.length === 0) break\n for (const row of rows) yield this.mapAuditLog(row)\n offset += pageSize\n }\n }\n\n // ── Stats ──────────────────────────────────────────────────────────────────\n\n async getOverviewStats(tenantId: string): Promise<OverviewStats> {\n const tc = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ?').get(tenantId) as { n: number } | undefined\n const gc = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ? AND gpc_detected = 1').get(tenantId) as { n: number } | undefined\n const vc = this.stmt('SELECT COUNT(*) as n FROM visitors WHERE tenant_id = ?').get(tenantId) as { n: number } | undefined\n const totalConsents = tc?.n ?? 0\n\n const recent = this.stmt(\n 'SELECT consent_json FROM consent_records WHERE tenant_id = ? ORDER BY created_at DESC LIMIT 500'\n ).all(tenantId) as unknown as { consent_json: string }[]\n\n let accepted = 0, rejected = 0\n for (const r of recent) {\n const vals = Object.values(JSON.parse(r.consent_json) as Record<string, string>)\n const grantedPct = vals.length > 0 ? vals.filter(v => v === 'granted').length / vals.length : 0\n if (grantedPct >= 0.8) accepted++\n else if (grantedPct <= 0.2) rejected++\n }\n const sample = recent.length || 1\n\n return {\n totalConsents,\n gpcDetectedCount: gc?.n ?? 0,\n totalVisitors: vc?.n ?? 0,\n acceptedPct: Math.round((accepted / sample) * 100),\n rejectedPct: Math.round((rejected / sample) * 100),\n }\n }\n\n async getCategoryStats(tenantId: string): Promise<CategoryStats> {\n const rows = this.stmt(\n 'SELECT consent_json FROM consent_records WHERE tenant_id = ? LIMIT 5000'\n ).all(tenantId) as unknown as { consent_json: string }[]\n const stats: CategoryStats = {}\n for (const row of rows) {\n const consent = JSON.parse(row.consent_json) as Record<string, string>\n for (const [key, status] of Object.entries(consent)) {\n if (!stats[key]) stats[key] = { granted: 0, denied: 0, objected: 0 }\n if (status === 'granted') stats[key]!.granted++\n else if (status === 'denied') stats[key]!.denied++\n else if (status === 'objected') stats[key]!.objected++\n }\n }\n return stats\n }\n\n async getTimeline(tenantId: string, days = 30): Promise<TimelineEntry[]> {\n const rows = this.stmt(\n `SELECT date(created_at) as date, COUNT(*) as count FROM consent_records WHERE tenant_id = ? AND created_at >= date('now', ?) GROUP BY date(created_at) ORDER BY date ASC`\n ).all(tenantId, `-${days} days`) as unknown as { date: string; count: number }[]\n return rows.map(r => ({ date: r.date, count: r.count }))\n }\n\n async getCountries(tenantId: string): Promise<CountryStat[]> {\n const rows = this.stmt(\n `SELECT v.country, COUNT(*) as count FROM consent_records cr JOIN visitors v ON v.visitor_id = cr.visitor_id WHERE cr.tenant_id = ? AND v.country IS NOT NULL GROUP BY v.country ORDER BY count DESC LIMIT 50`\n ).all(tenantId) as unknown as { country: string; count: number }[]\n return rows.map(r => ({ country: r.country, count: r.count }))\n }\n\n async getGpcStats(tenantId: string): Promise<GpcStats> {\n const total = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ?').get(tenantId) as { n: number } | undefined\n const detected = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ? AND gpc_detected = 1').get(tenantId) as { n: number } | undefined\n const t = total?.n ?? 0\n const d = detected?.n ?? 0\n return { detected: d, total: t, rate: t > 0 ? Math.round((d / t) * 100) : 0 }\n }\n\n // ── Tenants ────────────────────────────────────────────────────────────────\n\n async getTenants(): Promise<Tenant[]> {\n const rows = this.stmt('SELECT * FROM tenants ORDER BY name ASC').all() as unknown as RawTenant[]\n return rows.map(r => ({ id: r.id, name: r.name, slug: r.slug, createdAt: r.created_at, updatedAt: r.updated_at }))\n }\n\n async createTenant(data: CreateTenantInput): Promise<Tenant> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt('INSERT INTO tenants (id,name,slug,created_at,updated_at) VALUES (?,?,?,?,?)').run(id, data.name, data.slug, now, now)\n const row = this.stmt('SELECT * FROM tenants WHERE id = ?').get(id) as RawTenant | undefined\n if (!row) throw new Error('Failed to create tenant')\n return { id: row.id, name: row.name, slug: row.slug, createdAt: row.created_at, updatedAt: row.updated_at }\n }\n\n async updateTenant(id: string, data: UpdateTenantInput): Promise<Tenant> {\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?']\n const vals: (string | number)[] = [now]\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.slug != null) { fields.push('slug = ?'); vals.push(data.slug) }\n vals.push(id)\n this.stmt(`UPDATE tenants SET ${fields.join(', ')} WHERE id = ?`).run(...vals)\n const row = this.stmt('SELECT * FROM tenants WHERE id = ?').get(id) as RawTenant | undefined\n if (!row) throw new Error(`Tenant ${id} not found`)\n return { id: row.id, name: row.name, slug: row.slug, createdAt: row.created_at, updatedAt: row.updated_at }\n }\n\n async deleteTenant(id: string): Promise<void> {\n this.stmt('DELETE FROM tenants WHERE id = ?').run(id)\n }\n\n async purgeExpiredConsents(olderThanDays: number): Promise<number> {\n const cutoff = new Date(Date.now() - olderThanDays * 86_400_000).toISOString()\n const toDelete = this.stmt(\n 'SELECT visitor_id FROM consent_records WHERE created_at < ?'\n ).all(cutoff) as unknown as { visitor_id: string }[]\n for (const { visitor_id } of toDelete) {\n this.stmt('DELETE FROM consent_history WHERE visitor_id = ?').run(visitor_id)\n this.stmt('DELETE FROM consent_records WHERE visitor_id = ?').run(visitor_id)\n }\n return toDelete.length\n }\n\n // ── API Keys ───────────────────────────────────────────────────────────────\n\n private mapApiKey(r: RawApiKey): ApiKey {\n return { id: r.id, tenantId: r.tenant_id, keyHash: r.key_hash, name: r.name, isActive: r.is_active === 1, createdAt: r.created_at }\n }\n\n async createApiKey(data: CreateApiKeyInput): Promise<ApiKey> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt('INSERT INTO api_keys (id,tenant_id,key_hash,name,created_at) VALUES (?,?,?,?,?)').run(id, data.tenantId, data.keyHash, data.name, now)\n const row = this.stmt('SELECT * FROM api_keys WHERE id = ?').get(id) as RawApiKey | undefined\n if (!row) throw new Error('Failed to create API key')\n return this.mapApiKey(row)\n }\n\n async getApiKeyByHash(keyHash: string): Promise<ApiKey | null> {\n const row = this.stmt('SELECT * FROM api_keys WHERE key_hash = ? AND is_active = 1').get(keyHash) as RawApiKey | undefined\n return row ? this.mapApiKey(row) : null\n }\n\n async revokeApiKey(id: string): Promise<void> {\n this.stmt('UPDATE api_keys SET is_active = 0 WHERE id = ?').run(id)\n }\n\n async getApiKeys(tenantId: string): Promise<ApiKey[]> {\n const rows = this.stmt('SELECT * FROM api_keys WHERE tenant_id = ? ORDER BY created_at DESC').all(tenantId) as unknown as RawApiKey[]\n return rows.map(r => this.mapApiKey(r))\n }\n\n // ── Cookie Templates ───────────────────────────────────────────────────────\n\n private mapCookieTemplate(r: RawCookieTemplate): ServerCookieTemplate {\n return { id: r.id, tenantId: r.tenant_id, name: r.name, cookies: JSON.parse(r.cookies_json), createdAt: r.created_at, updatedAt: r.updated_at }\n }\n\n async createCookieTemplate(data: CreateCookieTemplateInput): Promise<ServerCookieTemplate> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt('INSERT INTO cookie_templates (id,tenant_id,name,cookies_json,created_at,updated_at) VALUES (?,?,?,?,?,?)').run(id, data.tenantId, data.name, JSON.stringify(data.cookies), now, now)\n return this.mapCookieTemplate(this.stmt('SELECT * FROM cookie_templates WHERE id = ?').get(id) as unknown as RawCookieTemplate)\n }\n\n async updateCookieTemplate(id: string, data: UpdateCookieTemplateInput): Promise<ServerCookieTemplate> {\n const now = new Date().toISOString()\n if (data.name !== undefined) this.stmt('UPDATE cookie_templates SET name = ?, updated_at = ? WHERE id = ?').run(data.name, now, id)\n if (data.cookies !== undefined) this.stmt('UPDATE cookie_templates SET cookies_json = ?, updated_at = ? WHERE id = ?').run(JSON.stringify(data.cookies), now, id)\n const row = this.stmt('SELECT * FROM cookie_templates WHERE id = ?').get(id) as RawCookieTemplate | undefined\n if (!row) throw new Error('Cookie template not found')\n return this.mapCookieTemplate(row)\n }\n\n async deleteCookieTemplate(id: string): Promise<void> {\n this.stmt('DELETE FROM cookie_templates WHERE id = ?').run(id)\n }\n\n async getCookieTemplate(id: string): Promise<ServerCookieTemplate | null> {\n const row = this.stmt('SELECT * FROM cookie_templates WHERE id = ?').get(id) as RawCookieTemplate | undefined\n return row ? this.mapCookieTemplate(row) : null\n }\n\n async getCookieTemplates(tenantId: string): Promise<ServerCookieTemplate[]> {\n const rows = this.stmt('SELECT * FROM cookie_templates WHERE tenant_id = ? ORDER BY name ASC').all(tenantId) as unknown as RawCookieTemplate[]\n return rows.map(r => this.mapCookieTemplate(r))\n }\n\n async copyCookieTemplate(id: string, newName: string): Promise<ServerCookieTemplate> {\n const src = await this.getCookieTemplate(id)\n if (!src) throw new Error('Cookie template not found')\n return this.createCookieTemplate({ tenantId: src.tenantId, name: newName, cookies: src.cookies })\n }\n\n // ── UI Templates ───────────────────────────────────────────────────────────\n\n private mapUITemplate(r: RawUITemplate): ServerUITemplate {\n const s = JSON.parse(r.settings_json) as Omit<ServerUITemplate, 'id' | 'tenantId' | 'name' | 'createdAt' | 'updatedAt'>\n return { id: r.id, tenantId: r.tenant_id, name: r.name, ...s, createdAt: r.created_at, updatedAt: r.updated_at }\n }\n\n async createUITemplate(data: CreateUITemplateInput): Promise<ServerUITemplate> {\n const id = randomUUID()\n const now = new Date().toISOString()\n const { tenantId, name, ...settings } = data\n this.stmt('INSERT INTO ui_templates (id,tenant_id,name,settings_json,created_at,updated_at) VALUES (?,?,?,?,?,?)').run(id, tenantId, name, JSON.stringify(settings), now, now)\n return this.mapUITemplate(this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as unknown as RawUITemplate)\n }\n\n async updateUITemplate(id: string, data: UpdateUITemplateInput): Promise<ServerUITemplate> {\n const now = new Date().toISOString()\n const row = this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as RawUITemplate | undefined\n if (!row) throw new Error('UI template not found')\n if (data.name !== undefined) this.stmt('UPDATE ui_templates SET name = ?, updated_at = ? WHERE id = ?').run(data.name, now, id)\n const { name: _n, ...settingsUpdate } = data\n if (Object.keys(settingsUpdate).length > 0) {\n const current = JSON.parse(row.settings_json) as Record<string, unknown>\n const merged = { ...current, ...settingsUpdate }\n this.stmt('UPDATE ui_templates SET settings_json = ?, updated_at = ? WHERE id = ?').run(JSON.stringify(merged), now, id)\n }\n return this.mapUITemplate(this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as unknown as RawUITemplate)\n }\n\n async deleteUITemplate(id: string): Promise<void> {\n this.stmt('DELETE FROM ui_templates WHERE id = ?').run(id)\n }\n\n async getUITemplate(id: string): Promise<ServerUITemplate | null> {\n const row = this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as RawUITemplate | undefined\n return row ? this.mapUITemplate(row) : null\n }\n\n async getUITemplates(tenantId: string): Promise<ServerUITemplate[]> {\n const rows = this.stmt('SELECT * FROM ui_templates WHERE tenant_id = ? ORDER BY name ASC').all(tenantId) as unknown as RawUITemplate[]\n return rows.map(r => this.mapUITemplate(r))\n }\n\n async copyUITemplate(id: string, newName: string): Promise<ServerUITemplate> {\n const src = await this.getUITemplate(id)\n if (!src) throw new Error('UI template not found')\n const { tenantId, mainBanner, gpcBanner, preferenceModal } = src\n return this.createUITemplate({ tenantId, name: newName, mainBanner, gpcBanner, preferenceModal })\n }\n\n // ── Profile summaries ──────────────────────────────────────────────────────\n\n private mapProfileSummary(r: RawProfileSummary): ProfileSummary {\n return {\n id: r.id,\n name: r.name,\n defaultLocale: r.default_locale,\n complianceGroup: (r.compliance_group ?? null) as ComplianceGroupId | null,\n version: r.version,\n isActive: r.is_active === 1,\n cookieTemplateName: r.cookie_template_name,\n uiTemplateName: r.ui_template_name,\n createdAt: r.created_at,\n updatedAt: r.updated_at,\n }\n }\n\n private readonly PROFILE_SUMMARY_SQL = `\n SELECT\n p.id, p.name, p.default_locale, p.version, p.created_at, p.updated_at,\n json_extract(p.profile_json, '$.complianceGroup') AS compliance_group,\n json_extract(p.profile_json, '$.isActive') AS is_active,\n json_extract(p.profile_json, '$.cookieTemplateId') AS cookie_template_id,\n json_extract(p.profile_json, '$.uiTemplateId') AS ui_template_id,\n ct.name AS cookie_template_name,\n ut.name AS ui_template_name\n FROM profiles p\n LEFT JOIN cookie_templates ct ON ct.id = json_extract(p.profile_json, '$.cookieTemplateId')\n LEFT JOIN ui_templates ut ON ut.id = json_extract(p.profile_json, '$.uiTemplateId')\n `\n\n async listProfilesSummary(tenantId: string): Promise<ProfileSummary[]> {\n const rows = this.stmt(\n `${this.PROFILE_SUMMARY_SQL} WHERE p.tenant_id = ? ORDER BY p.created_at ASC`\n ).all(tenantId) as unknown as RawProfileSummary[]\n return rows.map(r => this.mapProfileSummary(r))\n }\n\n async findProfilesUsingCookieTemplate(templateId: string): Promise<ProfileSummary[]> {\n const rows = this.stmt(\n `${this.PROFILE_SUMMARY_SQL} WHERE json_extract(p.profile_json, '$.cookieTemplateId') = ? ORDER BY p.name ASC`\n ).all(templateId) as unknown as RawProfileSummary[]\n return rows.map(r => this.mapProfileSummary(r))\n }\n\n async findProfilesUsingUITemplate(templateId: string): Promise<ProfileSummary[]> {\n const rows = this.stmt(\n `${this.PROFILE_SUMMARY_SQL} WHERE json_extract(p.profile_json, '$.uiTemplateId') = ? ORDER BY p.name ASC`\n ).all(templateId) as unknown as RawProfileSummary[]\n return rows.map(r => this.mapProfileSummary(r))\n }\n\n async getOptInStats(tenantId: string, filters: OptInFilters): Promise<OptInStats> {\n const conditions: string[] = ['cr.tenant_id = ?']\n const vals: (string | number | null)[] = [tenantId]\n if (filters.profileId) { conditions.push('cr.profile_id = ?'); vals.push(filters.profileId) }\n if (filters.from) { conditions.push('cr.created_at >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('cr.created_at <= ?'); vals.push(filters.to) }\n if (filters.locale) { conditions.push('cr.locale = ?'); vals.push(filters.locale) }\n const where = conditions.join(' AND ')\n\n const rows = this.stmt(\n `SELECT cr.locale, cr.consent_json FROM consent_records cr WHERE ${where}`\n ).all(...vals) as unknown as { locale: string; consent_json: string }[]\n\n let total = 0, granted = 0, denied = 0, managed = 0\n const byLocale: Record<string, { total: number; granted: number; denied: number; managed: number }> = {}\n\n for (const r of rows) {\n const statuses = Object.values(JSON.parse(r.consent_json) as Record<string, string>)\n const grantedPct = statuses.length > 0 ? statuses.filter(s => s === 'granted').length / statuses.length : 0\n const deniedPct = statuses.length > 0 ? statuses.filter(s => s === 'denied').length / statuses.length : 0\n total++\n const loc = r.locale\n if (!byLocale[loc]) byLocale[loc] = { total: 0, granted: 0, denied: 0, managed: 0 }\n byLocale[loc]!.total++\n if (grantedPct >= 0.9) { granted++; byLocale[loc]!.granted++ }\n else if (deniedPct >= 0.9) { denied++; byLocale[loc]!.denied++ }\n else { managed++; byLocale[loc]!.managed++ }\n }\n\n const dateRows = this.stmt(\n `SELECT date(cr.created_at) as d, cr.consent_json FROM consent_records cr WHERE ${where} ORDER BY d ASC`\n ).all(...vals) as unknown as { d: string; consent_json: string }[]\n\n const dateMap = new Map<string, { total: number; granted: number; denied: number; managed: number }>()\n for (const r of dateRows) {\n const entry = dateMap.get(r.d) ?? { total: 0, granted: 0, denied: 0, managed: 0 }\n const statuses = Object.values(JSON.parse(r.consent_json) as Record<string, string>)\n const grantedPct = statuses.length > 0 ? statuses.filter(s => s === 'granted').length / statuses.length : 0\n const deniedPct = statuses.length > 0 ? statuses.filter(s => s === 'denied').length / statuses.length : 0\n entry.total++\n if (grantedPct >= 0.9) entry.granted++\n else if (deniedPct >= 0.9) entry.denied++\n else entry.managed++\n dateMap.set(r.d, entry)\n }\n\n const byDate = Array.from(dateMap.entries()).map(([date, v]) => ({ date, ...v }))\n return {\n total, granted, denied, managed,\n grantedPct: total > 0 ? Math.round((granted / total) * 1000) / 10 : 0,\n deniedPct: total > 0 ? Math.round((denied / total) * 1000) / 10 : 0,\n managedPct: total > 0 ? Math.round((managed / total) * 1000) / 10 : 0,\n byLocale,\n byDate,\n }\n }\n}\n","import type { Database as DB, Statement } from 'node-sqlite3-wasm'\n\nconst MAX_PAGE_SIZE = 500\nimport { randomUUID, randomProfileId } from '../../utils/crypto'\nimport { resolveStoragePaths } from '../../utils/storage-path'\nimport {\n SEED_SQL,\n SCHEMA_SQL_SQLITE,\n SCHEMA_SQL_SQLITE_API_KEYS,\n SCHEMA_SQL_SQLITE_ENTERPRISE,\n SCHEMA_SQL_SQLITE_TEMPLATES,\n} from '../seed-data'\nimport type {\n StorageAdapter,\n StorageConfig,\n Profile,\n ProfileConfig,\n CreateProfileInput,\n UpdateProfileInput,\n ConsentDbRecord,\n ConsentHistoryEntry,\n ConsentValue,\n CreateConsentInput,\n UpdateConsentInput,\n ConsentFilters,\n Visitor,\n VisitorFilters,\n CreateVisitorInput,\n UpdateVisitorInput,\n AdminUser,\n CreateUserInput,\n UpdateUserInput,\n Role,\n CreateRoleInput,\n UpdateRoleInput,\n Permission,\n AuditLog,\n AuditFilters,\n CreateAuditLogInput,\n OverviewStats,\n CategoryStats,\n TimelineEntry,\n CountryStat,\n GpcStats,\n Tenant,\n ApiKey,\n CreateApiKeyInput,\n CreateTenantInput,\n UpdateTenantInput,\n ServerCookieTemplate,\n ServerUITemplate,\n CreateCookieTemplateInput,\n UpdateCookieTemplateInput,\n CreateUITemplateInput,\n UpdateUITemplateInput,\n ProfileSummary,\n OptInStats,\n OptInFilters,\n ComplianceGroupId,\n} from '@consenti/types'\n\ninterface RawProfile {\n id: string; tenant_id: string; name: string; default_locale: string\n version: number; profile_json: string\n created_at: string; updated_at: string\n}\ninterface RawConsent {\n id: string; tenant_id: string; visitor_id: string; profile_id: string\n profile_version: number; locale: string; consent_json: string\n gpc_detected: number; source: string; created_at: string; updated_at: string\n age_verified?: number; parental_consent_token?: string | null; tcf_string?: string | null\n}\ninterface RawConsentHistory {\n id: string; tenant_id: string; consent_record_id: string; visitor_id: string\n old_json: string | null; new_json: string; action: string; created_at: string\n}\ninterface RawVisitor {\n id: string; tenant_id: string; visitor_id: string\n country: string | null; region: string | null; city: string | null\n ip_hash: string | null; user_agent_hash: string | null\n first_seen: string; last_seen: string\n}\ninterface RawUser {\n id: string; tenant_id: string; name: string; email: string\n password_hash: string; is_active: number; created_at: string; updated_at: string\n totp_secret?: string | null; totp_enabled?: number\n allowed_tenants?: string | null\n}\ninterface RawProfileSummary {\n id: string; name: string; default_locale: string; version: number\n compliance_group: string | null; is_active: number\n cookie_template_name: string | null; ui_template_name: string | null\n created_at: string; updated_at: string\n}\ninterface RawRole {\n id: string; tenant_id: string; name: string; description: string | null\n}\ninterface RawPermission {\n id: string; name: string; description: string | null\n}\ninterface RawAuditLog {\n id: string; tenant_id: string; user_id: string | null; action: string\n resource_type: string; resource_id: string | null\n old_data: string | null; new_data: string | null; created_at: string\n}\ninterface RawTenant {\n id: string; name: string; slug: string; created_at: string; updated_at: string\n}\ninterface RawApiKey {\n id: string; tenant_id: string; key_hash: string; name: string; is_active: number; created_at: string\n}\ninterface RawCookieTemplate {\n id: string; tenant_id: string; name: string; cookies_json: string; created_at: string; updated_at: string\n}\ninterface RawUITemplate {\n id: string; tenant_id: string; name: string; settings_json: string; created_at: string; updated_at: string\n}\n\n\n// node-sqlite3-wasm statements are NOT garbage-collected — they must be\n// finalized explicitly. All cached statements are finalized in disconnect().\n// Parameter binding uses run(array) / all(array) — not spread — per the WASM API.\n\ntype Val = string | number | null\n\nexport class NodeSqlite3WasmAdapter implements StorageAdapter {\n private db!: DB\n private cache = new Map<string, Statement>()\n\n constructor(private config: StorageConfig) { }\n\n private stmt(sql: string): Statement {\n let s = this.cache.get(sql)\n if (!s) { s = this.db.prepare(sql); this.cache.set(sql, s) }\n return s\n }\n\n async connect(): Promise<void> {\n // Lazy: only loaded when this driver is actually selected — allows the package\n // to be an optional peer dep without crashing on startup for other drivers.\n const mod = await import('node-sqlite3-wasm').catch(() => {\n throw new Error(\"driver 'node-sqlite3-wasm' requires: npm install node-sqlite3-wasm\")\n }) as { default: { Database: new (path: string) => DB } }\n const { dbPath } = resolveStoragePaths(this.config.path ?? './consenti-data', 'node-sqlite3-wasm')\n this.db = new mod.default.Database(dbPath)\n this.db.exec('PRAGMA journal_mode=WAL')\n this.db.exec('PRAGMA foreign_keys=ON')\n this.db.exec('PRAGMA synchronous=NORMAL')\n await this.migrate()\n }\n\n async disconnect(): Promise<void> {\n // Finalize all prepared statements before closing — WASM objects are not\n // GC'd and will leak if not explicitly freed.\n for (const stmt of this.cache.values()) {\n stmt.finalize()\n }\n this.cache.clear()\n this.db.close()\n }\n\n async migrate(): Promise<void> {\n const row = this.stmt('PRAGMA user_version').get() as { user_version: number } | null\n const ver = row?.user_version ?? 0\n if (ver < 1) {\n this.db.exec(SCHEMA_SQL_SQLITE)\n this.db.exec(SEED_SQL)\n this.db.exec('PRAGMA user_version = 1')\n }\n if (ver < 2) {\n this.db.exec(SCHEMA_SQL_SQLITE_API_KEYS)\n this.db.exec('PRAGMA user_version = 2')\n }\n if (ver < 3) {\n this.db.exec(SCHEMA_SQL_SQLITE_ENTERPRISE)\n this.db.exec('PRAGMA user_version = 3')\n }\n if (ver < 4) {\n this.db.exec('ALTER TABLE user_roles ADD COLUMN tenant_id TEXT NOT NULL DEFAULT \\'default\\'')\n this.db.exec('PRAGMA user_version = 4')\n }\n if (ver < 5) {\n this.db.exec(SCHEMA_SQL_SQLITE_TEMPLATES)\n this.db.exec('PRAGMA user_version = 5')\n }\n if (ver < 6) {\n this.db.exec('ALTER TABLE users ADD COLUMN allowed_tenants TEXT')\n this.db.exec('PRAGMA user_version = 6')\n }\n\n this.db.exec(`\n CREATE INDEX IF NOT EXISTS idx_profiles_tenant_compliance_active\n ON profiles (tenant_id, json_extract(profile_json,'$.complianceGroup'), json_extract(profile_json,'$.isActive'));\n CREATE INDEX IF NOT EXISTS idx_profiles_tenant\n ON profiles (tenant_id);\n CREATE INDEX IF NOT EXISTS idx_consents_tenant_profile_date\n ON consent_records (tenant_id, profile_id, created_at);\n CREATE INDEX IF NOT EXISTS idx_consents_visitor\n ON consent_records (visitor_id);\n CREATE INDEX IF NOT EXISTS idx_visitors_tenant\n ON visitors (tenant_id);\n CREATE INDEX IF NOT EXISTS idx_audit_tenant_date\n ON audit_logs (tenant_id, created_at);\n `)\n }\n\n // ── Profiles ──────────────────────────────────────────────────────────────\n\n private mapProfile(row: RawProfile): Profile {\n return {\n id: row.id, tenantId: row.tenant_id, name: row.name,\n defaultLocale: row.default_locale, version: row.version,\n profileJson: JSON.parse(row.profile_json) as ProfileConfig,\n createdAt: row.created_at, updatedAt: row.updated_at,\n }\n }\n\n async createProfile(data: CreateProfileInput): Promise<Profile> {\n const id = randomProfileId()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO profiles (id,tenant_id,name,default_locale,profile_json,created_at,updated_at) VALUES (?,?,?,?,?,?,?)'\n ).run([id, data.tenantId, data.name, data.defaultLocale, JSON.stringify(data.profileJson), now, now])\n const profile = await this.getProfile(id)\n if (!profile) throw new Error('Failed to create profile')\n return profile\n }\n\n async updateProfile(id: string, data: UpdateProfileInput): Promise<Profile> {\n const existing = await this.getProfile(id)\n if (!existing) throw new Error(`Profile ${id} not found`)\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?', 'version = version + 1']\n const vals: Val[] = [now]\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.defaultLocale != null) { fields.push('default_locale = ?'); vals.push(data.defaultLocale) }\n if (data.profileJson != null) { fields.push('profile_json = ?'); vals.push(JSON.stringify(data.profileJson)) }\n vals.push(id)\n this.stmt(`UPDATE profiles SET ${fields.join(', ')} WHERE id = ?`).run(vals)\n const updated = await this.getProfile(id)\n if (!updated) throw new Error('Failed to update profile')\n return updated\n }\n\n async deleteProfile(id: string): Promise<void> {\n this.stmt('DELETE FROM profiles WHERE id = ?').run(id)\n }\n\n async getProfile(id: string): Promise<Profile | null> {\n const row = this.stmt('SELECT * FROM profiles WHERE id = ?').get(id) as RawProfile | null\n return row ? this.mapProfile(row) : null\n }\n\n async getProfiles(tenantId: string): Promise<Profile[]> {\n const rows = this.stmt('SELECT * FROM profiles WHERE tenant_id = ? ORDER BY created_at ASC').all(tenantId) as unknown as RawProfile[]\n return rows.map(r => this.mapProfile(r))\n }\n\n async findActiveProfileByComplianceGroup(tenantId: string, complianceGroup: string): Promise<Profile | null> {\n // Fetch all tenant profiles and filter in memory — wasm Statement.get() only accepts a single bind value\n const profiles = await this.getProfiles(tenantId)\n return profiles.find(p => p.profileJson.complianceGroup === complianceGroup && p.profileJson.isActive) ?? null\n }\n\n // ── Consents ──────────────────────────────────────────────────────────────\n\n private mapConsent(row: RawConsent): ConsentDbRecord {\n return {\n id: row.id, tenantId: row.tenant_id, visitorId: row.visitor_id,\n profileId: row.profile_id, profileVersion: row.profile_version,\n locale: row.locale, consentJson: JSON.parse(row.consent_json) as ConsentValue,\n gpcDetected: row.gpc_detected === 1,\n source: row.source as ConsentDbRecord['source'],\n ...(row.age_verified != null && row.age_verified !== 0 ? { ageVerified: true } : {}),\n ...(row.parental_consent_token != null ? { parentalConsentToken: row.parental_consent_token } : {}),\n ...(row.tcf_string != null ? { tcfString: row.tcf_string } : {}),\n createdAt: row.created_at, updatedAt: row.updated_at,\n }\n }\n\n async createConsent(data: CreateConsentInput): Promise<ConsentDbRecord> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO consent_records (id,tenant_id,visitor_id,profile_id,profile_version,locale,consent_json,gpc_detected,source,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)'\n ).run([id, data.tenantId, data.visitorId, data.profileId, data.profileVersion, data.locale, JSON.stringify(data.consentJson), data.gpcDetected ? 1 : 0, data.source, now, now])\n const histId = randomUUID()\n this.stmt(\n 'INSERT INTO consent_history (id,tenant_id,consent_record_id,visitor_id,old_json,new_json,action,created_at) VALUES (?,?,?,?,?,?,?,?)'\n ).run([histId, data.tenantId, id, data.visitorId, null, JSON.stringify(data.consentJson), 'created', now])\n const record = await this.getConsent(data.visitorId)\n if (!record) throw new Error('Failed to create consent')\n return record\n }\n\n async updateConsent(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord> {\n const existing = await this.getConsent(visitorId)\n if (!existing) throw new Error(`Consent for visitor ${visitorId} not found`)\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?', 'consent_json = ?']\n const vals: Val[] = [now, JSON.stringify(data.consentJson)]\n if (data.locale != null) { fields.push('locale = ?'); vals.push(data.locale) }\n if (data.gpcDetected != null) { fields.push('gpc_detected = ?'); vals.push(data.gpcDetected ? 1 : 0) }\n vals.push(visitorId)\n this.stmt(`UPDATE consent_records SET ${fields.join(', ')} WHERE visitor_id = ?`).run(vals)\n const histId = randomUUID()\n this.stmt(\n 'INSERT INTO consent_history (id,tenant_id,consent_record_id,visitor_id,old_json,new_json,action,created_at) VALUES (?,?,?,?,?,?,?,?)'\n ).run([histId, existing.tenantId, existing.id, visitorId, JSON.stringify(existing.consentJson), JSON.stringify(data.consentJson), 'updated', now])\n const updated = await this.getConsent(visitorId)\n if (!updated) throw new Error('Failed to update consent')\n return updated\n }\n\n async deleteConsent(visitorId: string): Promise<void> {\n this.stmt('DELETE FROM consent_history WHERE visitor_id = ?').run(visitorId)\n this.stmt('DELETE FROM consent_records WHERE visitor_id = ?').run(visitorId)\n }\n\n async getConsent(visitorId: string): Promise<ConsentDbRecord | null> {\n const row = this.stmt('SELECT * FROM consent_records WHERE visitor_id = ?').get(visitorId) as RawConsent | null\n return row ? this.mapConsent(row) : null\n }\n\n async getConsents(filters: ConsentFilters): Promise<ConsentDbRecord[]> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: Val[] = [filters.tenantId]\n if (filters.profileId) { conditions.push('profile_id = ?'); vals.push(filters.profileId) }\n if (filters.from) { conditions.push('created_at >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('created_at <= ?'); vals.push(filters.to) }\n const limit = Math.min(filters.limit ?? 50, MAX_PAGE_SIZE)\n const offset = ((filters.page ?? 1) - 1) * limit\n const rows = this.stmt(\n `SELECT * FROM consent_records WHERE ${conditions.join(' AND ')} ORDER BY created_at DESC LIMIT ? OFFSET ?`\n ).all([...vals, limit, offset]) as unknown as RawConsent[]\n return rows.map(r => this.mapConsent(r))\n }\n\n async *streamConsents(filters: ConsentFilters): AsyncIterable<ConsentDbRecord> {\n const pageSize = 500\n let offset = 0\n while (true) {\n const rows = this.stmt(\n 'SELECT * FROM consent_records WHERE tenant_id = ? LIMIT ? OFFSET ?'\n ).all([filters.tenantId, pageSize, offset]) as unknown as RawConsent[]\n if (rows.length === 0) break\n for (const row of rows) yield this.mapConsent(row)\n offset += pageSize\n }\n }\n\n async getConsentHistory(visitorId: string): Promise<ConsentHistoryEntry[]> {\n const rows = this.stmt(\n 'SELECT * FROM consent_history WHERE visitor_id = ? ORDER BY created_at ASC'\n ).all(visitorId) as unknown as RawConsentHistory[]\n return rows.map(r => ({\n id: r.id, tenantId: r.tenant_id, consentRecordId: r.consent_record_id,\n visitorId: r.visitor_id,\n oldJson: r.old_json != null ? JSON.parse(r.old_json) as ConsentValue : null,\n newJson: JSON.parse(r.new_json) as ConsentValue,\n action: r.action as ConsentHistoryEntry['action'],\n createdAt: r.created_at,\n }))\n }\n\n // ── Visitors ──────────────────────────────────────────────────────────────\n\n private mapVisitor(row: RawVisitor): Visitor {\n return {\n id: row.id, tenantId: row.tenant_id, visitorId: row.visitor_id,\n firstSeen: row.first_seen, lastSeen: row.last_seen,\n ...(row.country != null ? { country: row.country } : {}),\n ...(row.region != null ? { region: row.region } : {}),\n ...(row.city != null ? { city: row.city } : {}),\n ...(row.ip_hash != null ? { ipHash: row.ip_hash } : {}),\n ...(row.user_agent_hash != null ? { userAgentHash: row.user_agent_hash } : {}),\n }\n }\n\n async createVisitor(data: CreateVisitorInput): Promise<Visitor> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO visitors (id,tenant_id,visitor_id,country,region,city,ip_hash,user_agent_hash,first_seen,last_seen) VALUES (?,?,?,?,?,?,?,?,?,?)'\n ).run([id, data.tenantId, data.visitorId, data.country ?? null, data.region ?? null, data.city ?? null, data.ipHash ?? null, data.userAgentHash ?? null, now, now])\n const visitor = await this.getVisitor(data.visitorId)\n if (!visitor) throw new Error('Failed to create visitor')\n return visitor\n }\n\n async updateVisitor(visitorId: string, data: UpdateVisitorInput): Promise<Visitor> {\n const now = new Date().toISOString()\n const fields: string[] = ['last_seen = ?']\n const vals: Val[] = [data.lastSeen ?? now]\n if (data.country != null) { fields.push('country = ?'); vals.push(data.country) }\n if (data.region != null) { fields.push('region = ?'); vals.push(data.region) }\n if (data.city != null) { fields.push('city = ?'); vals.push(data.city) }\n vals.push(visitorId)\n this.stmt(`UPDATE visitors SET ${fields.join(', ')} WHERE visitor_id = ?`).run(vals)\n const visitor = await this.getVisitor(visitorId)\n if (!visitor) throw new Error(`Visitor ${visitorId} not found`)\n return visitor\n }\n\n async deleteVisitor(visitorId: string): Promise<void> {\n this.stmt('DELETE FROM visitors WHERE visitor_id = ?').run(visitorId)\n }\n\n async getVisitor(visitorId: string): Promise<Visitor | null> {\n const row = this.stmt('SELECT * FROM visitors WHERE visitor_id = ?').get(visitorId) as RawVisitor | null\n return row ? this.mapVisitor(row) : null\n }\n\n async getVisitors(filters: VisitorFilters): Promise<Visitor[]> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: Val[] = [filters.tenantId]\n if (filters.from) { conditions.push('first_seen >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('first_seen <= ?'); vals.push(filters.to) }\n const limit = Math.min(filters.limit ?? 50, MAX_PAGE_SIZE)\n const offset = ((filters.page ?? 1) - 1) * limit\n const rows = this.stmt(\n `SELECT * FROM visitors WHERE ${conditions.join(' AND ')} ORDER BY last_seen DESC LIMIT ? OFFSET ?`\n ).all([...vals, limit, offset]) as unknown as RawVisitor[]\n return rows.map(r => this.mapVisitor(r))\n }\n\n // ── Users ─────────────────────────────────────────────────────────────────\n\n private mapUser(row: RawUser): AdminUser {\n const allowedTenants: string[] = row.allowed_tenants\n ? JSON.parse(row.allowed_tenants) as string[]\n : []\n return {\n id: row.id, tenantId: row.tenant_id, name: row.name, email: row.email,\n passwordHash: row.password_hash, isActive: row.is_active === 1,\n totpEnabled: row.totp_enabled === 1,\n ...(row.totp_secret != null ? { totpSecret: row.totp_secret } : {}),\n allowedTenants,\n createdAt: row.created_at, updatedAt: row.updated_at,\n }\n }\n\n async createUser(data: CreateUserInput): Promise<AdminUser> {\n const id = randomUUID()\n const now = new Date().toISOString()\n const allowedTenantsJson = data.allowedTenants?.length ? JSON.stringify(data.allowedTenants) : null\n this.stmt(\n 'INSERT INTO users (id,tenant_id,name,email,password_hash,allowed_tenants,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?)'\n ).run([id, data.tenantId, data.name, data.email, data.passwordHash, allowedTenantsJson, now, now])\n const user = await this.getUserByEmail(data.email)\n if (!user) throw new Error('Failed to create user')\n return user\n }\n\n async updateUser(id: string, data: UpdateUserInput): Promise<AdminUser> {\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?']\n const vals: Val[] = [now]\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.email != null) { fields.push('email = ?'); vals.push(data.email) }\n if (data.passwordHash != null) { fields.push('password_hash = ?'); vals.push(data.passwordHash) }\n if (data.isActive != null) { fields.push('is_active = ?'); vals.push(data.isActive ? 1 : 0) }\n if ('totpSecret' in data) { fields.push('totp_secret = ?'); vals.push(data.totpSecret ?? null) }\n if (data.totpEnabled != null) { fields.push('totp_enabled = ?'); vals.push(data.totpEnabled ? 1 : 0) }\n if ('allowedTenants' in data) {\n fields.push('allowed_tenants = ?')\n vals.push(data.allowedTenants?.length ? JSON.stringify(data.allowedTenants) : null)\n }\n vals.push(id)\n this.stmt(`UPDATE users SET ${fields.join(', ')} WHERE id = ?`).run(vals)\n const row = this.stmt('SELECT * FROM users WHERE id = ?').get(id) as RawUser | null\n if (!row) throw new Error(`User ${id} not found`)\n return this.mapUser(row)\n }\n\n async deleteUser(id: string): Promise<void> {\n this.stmt('DELETE FROM user_roles WHERE user_id = ?').run(id)\n this.stmt('DELETE FROM users WHERE id = ?').run(id)\n }\n\n async getUserById(id: string): Promise<AdminUser | null> {\n const row = this.stmt('SELECT * FROM users WHERE id = ?').get(id) as RawUser | null\n return row ? this.mapUser(row) : null\n }\n\n async getUserByEmail(email: string): Promise<AdminUser | null> {\n const row = this.stmt('SELECT * FROM users WHERE email = ?').get(email) as RawUser | null\n return row ? this.mapUser(row) : null\n }\n\n async getUsers(tenantId: string): Promise<AdminUser[]> {\n const rows = this.stmt('SELECT * FROM users WHERE tenant_id = ? ORDER BY created_at ASC').all(tenantId) as unknown as RawUser[]\n return rows.map(r => this.mapUser(r))\n }\n\n async countUsers(tenantId?: string): Promise<number> {\n const row = tenantId\n ? this.stmt('SELECT COUNT(*) as n FROM users WHERE tenant_id = ?').get(tenantId) as { n: number } | null\n : this.stmt('SELECT COUNT(*) as n FROM users').get() as { n: number } | null\n return row?.n ?? 0\n }\n\n // ── Roles & Permissions ───────────────────────────────────────────────────\n\n async getRoles(tenantId: string): Promise<Role[]> {\n const rows = this.stmt('SELECT * FROM roles WHERE tenant_id = ?').all(tenantId) as unknown as RawRole[]\n return rows.map(r => ({ id: r.id, tenantId: r.tenant_id, name: r.name, ...(r.description != null ? { description: r.description } : {}) }))\n }\n\n async createRole(data: CreateRoleInput): Promise<Role> {\n const id = randomUUID()\n this.stmt('INSERT INTO roles (id,tenant_id,name,description) VALUES (?,?,?,?)').run(\n [id, data.tenantId, data.name, data.description ?? null]\n )\n const row = this.stmt('SELECT * FROM roles WHERE id = ?').get(id) as RawRole | null\n if (!row) throw new Error('Failed to create role')\n return { id: row.id, tenantId: row.tenant_id, name: row.name, ...(row.description != null ? { description: row.description } : {}) }\n }\n\n async updateRole(id: string, data: UpdateRoleInput): Promise<Role> {\n const fields: string[] = []\n const vals: Val[] = []\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.description != null) { fields.push('description = ?'); vals.push(data.description) }\n if (fields.length > 0) {\n vals.push(id)\n this.stmt(`UPDATE roles SET ${fields.join(', ')} WHERE id = ?`).run(vals)\n }\n const row = this.stmt('SELECT * FROM roles WHERE id = ?').get(id) as RawRole | null\n if (!row) throw new Error(`Role ${id} not found`)\n return { id: row.id, tenantId: row.tenant_id, name: row.name, ...(row.description != null ? { description: row.description } : {}) }\n }\n\n async deleteRole(id: string): Promise<void> {\n this.stmt('DELETE FROM role_permissions WHERE role_id = ?').run(id)\n this.stmt('DELETE FROM user_roles WHERE role_id = ?').run(id)\n this.stmt('DELETE FROM roles WHERE id = ?').run(id)\n }\n\n async getAllPermissions(): Promise<Permission[]> {\n const rows = this.stmt('SELECT * FROM permissions ORDER BY name ASC').all() as unknown as RawPermission[]\n return rows.map(r => ({ id: r.id, name: r.name, ...(r.description != null ? { description: r.description } : {}) }))\n }\n\n async assignPermissionToRole(roleId: string, permissionId: string): Promise<void> {\n this.stmt('INSERT OR IGNORE INTO role_permissions (role_id,permission_id) VALUES (?,?)').run([roleId, permissionId])\n }\n\n async revokePermissionFromRole(roleId: string, permissionId: string): Promise<void> {\n this.stmt('DELETE FROM role_permissions WHERE role_id = ? AND permission_id = ?').run([roleId, permissionId])\n }\n\n async getPermissionsForRole(roleId: string): Promise<Permission[]> {\n const rows = this.stmt(\n 'SELECT p.* FROM permissions p JOIN role_permissions rp ON rp.permission_id = p.id WHERE rp.role_id = ?'\n ).all(roleId) as unknown as RawPermission[]\n return rows.map(r => ({ id: r.id, name: r.name, ...(r.description != null ? { description: r.description } : {}) }))\n }\n\n async getUserRoles(userId: string, tenantId?: string): Promise<Role[]> {\n const rows = tenantId\n ? this.stmt(\n 'SELECT r.* FROM roles r JOIN user_roles ur ON ur.role_id = r.id WHERE ur.user_id = ? AND ur.tenant_id = ?'\n ).all([userId, tenantId]) as unknown as RawRole[]\n : this.stmt(\n 'SELECT r.* FROM roles r JOIN user_roles ur ON ur.role_id = r.id WHERE ur.user_id = ?'\n ).all(userId) as unknown as RawRole[]\n return rows.map(r => ({ id: r.id, tenantId: r.tenant_id, name: r.name, ...(r.description != null ? { description: r.description } : {}) }))\n }\n\n async assignRole(userId: string, roleId: string, tenantId = 'default'): Promise<void> {\n this.stmt('INSERT OR IGNORE INTO user_roles (user_id, role_id, tenant_id) VALUES (?,?,?)').run([userId, roleId, tenantId])\n }\n\n async revokeRole(userId: string, roleId: string, tenantId?: string): Promise<void> {\n if (tenantId) {\n this.stmt('DELETE FROM user_roles WHERE user_id = ? AND role_id = ? AND tenant_id = ?').run([userId, roleId, tenantId])\n } else {\n this.stmt('DELETE FROM user_roles WHERE user_id = ? AND role_id = ?').run([userId, roleId])\n }\n }\n\n // ── Audit ─────────────────────────────────────────────────────────────────\n\n async createLog(data: CreateAuditLogInput): Promise<void> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO audit_logs (id,tenant_id,user_id,action,resource_type,resource_id,old_data,new_data,created_at) VALUES (?,?,?,?,?,?,?,?,?)'\n ).run([\n id, data.tenantId, data.userId ?? null, data.action, data.resourceType,\n data.resourceId ?? null,\n data.oldData != null ? JSON.stringify(data.oldData) : null,\n data.newData != null ? JSON.stringify(data.newData) : null,\n now,\n ])\n }\n\n async getLogs(filters: AuditFilters): Promise<AuditLog[]> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: Val[] = [filters.tenantId]\n if (filters.action) { conditions.push('action = ?'); vals.push(filters.action) }\n if (filters.resourceType) { conditions.push('resource_type = ?'); vals.push(filters.resourceType) }\n if (filters.from) { conditions.push('created_at >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('created_at <= ?'); vals.push(filters.to) }\n const limit = Math.min(filters.limit ?? 50, MAX_PAGE_SIZE)\n const offset = ((filters.page ?? 1) - 1) * limit\n const rows = this.stmt(\n `SELECT * FROM audit_logs WHERE ${conditions.join(' AND ')} ORDER BY created_at DESC LIMIT ? OFFSET ?`\n ).all([...vals, limit, offset]) as unknown as RawAuditLog[]\n return rows.map(r => this.mapAuditLog(r))\n }\n\n private mapAuditLog(r: RawAuditLog): AuditLog {\n return {\n id: r.id, tenantId: r.tenant_id, action: r.action,\n resourceType: r.resource_type, createdAt: r.created_at,\n ...(r.user_id != null ? { userId: r.user_id } : {}),\n ...(r.resource_id != null ? { resourceId: r.resource_id } : {}),\n ...(r.old_data != null ? { oldData: JSON.parse(r.old_data) as unknown } : {}),\n ...(r.new_data != null ? { newData: JSON.parse(r.new_data) as unknown } : {}),\n }\n }\n\n async *streamAuditLogs(filters: AuditFilters): AsyncIterable<AuditLog> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: Val[] = [filters.tenantId]\n if (filters.action) { conditions.push('action = ?'); vals.push(filters.action) }\n if (filters.from) { conditions.push('created_at >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('created_at <= ?'); vals.push(filters.to) }\n const pageSize = 500\n let offset = 0\n while (true) {\n const rows = this.stmt(\n `SELECT * FROM audit_logs WHERE ${conditions.join(' AND ')} ORDER BY created_at DESC LIMIT ? OFFSET ?`\n ).all([...vals, pageSize, offset]) as unknown as RawAuditLog[]\n if (rows.length === 0) break\n for (const row of rows) yield this.mapAuditLog(row)\n offset += pageSize\n }\n }\n\n // ── Stats ──────────────────────────────────────────────────────────────────\n\n async getOverviewStats(tenantId: string): Promise<OverviewStats> {\n const tc = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ?').get(tenantId) as { n: number } | null\n const gc = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ? AND gpc_detected = 1').get(tenantId) as { n: number } | null\n const vc = this.stmt('SELECT COUNT(*) as n FROM visitors WHERE tenant_id = ?').get(tenantId) as { n: number } | null\n const totalConsents = tc?.n ?? 0\n\n const recent = this.stmt(\n 'SELECT consent_json FROM consent_records WHERE tenant_id = ? ORDER BY created_at DESC LIMIT 500'\n ).all(tenantId) as unknown as { consent_json: string }[]\n\n let accepted = 0, rejected = 0\n for (const r of recent) {\n const vals = Object.values(JSON.parse(r.consent_json) as Record<string, string>)\n const grantedPct = vals.length > 0 ? vals.filter(v => v === 'granted').length / vals.length : 0\n if (grantedPct >= 0.8) accepted++\n else if (grantedPct <= 0.2) rejected++\n }\n const sample = recent.length || 1\n\n return {\n totalConsents,\n gpcDetectedCount: gc?.n ?? 0,\n totalVisitors: vc?.n ?? 0,\n acceptedPct: Math.round((accepted / sample) * 100),\n rejectedPct: Math.round((rejected / sample) * 100),\n }\n }\n\n async getCategoryStats(tenantId: string): Promise<CategoryStats> {\n const rows = this.stmt(\n 'SELECT consent_json FROM consent_records WHERE tenant_id = ? LIMIT 5000'\n ).all(tenantId) as unknown as { consent_json: string }[]\n const stats: CategoryStats = {}\n for (const row of rows) {\n const consent = JSON.parse(row.consent_json) as Record<string, string>\n for (const [key, status] of Object.entries(consent)) {\n if (!stats[key]) stats[key] = { granted: 0, denied: 0, objected: 0 }\n if (status === 'granted') stats[key]!.granted++\n else if (status === 'denied') stats[key]!.denied++\n else if (status === 'objected') stats[key]!.objected++\n }\n }\n return stats\n }\n\n async getTimeline(tenantId: string, days = 30): Promise<TimelineEntry[]> {\n const rows = this.stmt(\n `SELECT date(created_at) as date, COUNT(*) as count FROM consent_records WHERE tenant_id = ? AND created_at >= date('now', ?) GROUP BY date(created_at) ORDER BY date ASC`\n ).all([tenantId, `-${days} days`]) as unknown as { date: string; count: number }[]\n return rows.map(r => ({ date: r.date, count: r.count }))\n }\n\n async getCountries(tenantId: string): Promise<CountryStat[]> {\n const rows = this.stmt(\n `SELECT v.country, COUNT(*) as count FROM consent_records cr JOIN visitors v ON v.visitor_id = cr.visitor_id WHERE cr.tenant_id = ? AND v.country IS NOT NULL GROUP BY v.country ORDER BY count DESC LIMIT 50`\n ).all(tenantId) as unknown as { country: string; count: number }[]\n return rows.map(r => ({ country: r.country, count: r.count }))\n }\n\n async getGpcStats(tenantId: string): Promise<GpcStats> {\n const total = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ?').get(tenantId) as { n: number } | null\n const detected = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ? AND gpc_detected = 1').get(tenantId) as { n: number } | null\n const t = total?.n ?? 0\n const d = detected?.n ?? 0\n return { detected: d, total: t, rate: t > 0 ? Math.round((d / t) * 100) : 0 }\n }\n\n // ── Tenants ────────────────────────────────────────────────────────────────\n\n async getTenants(): Promise<Tenant[]> {\n const rows = this.stmt('SELECT * FROM tenants ORDER BY name ASC').all() as unknown as RawTenant[]\n return rows.map(r => ({ id: r.id, name: r.name, slug: r.slug, createdAt: r.created_at, updatedAt: r.updated_at }))\n }\n\n async createTenant(data: CreateTenantInput): Promise<Tenant> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt('INSERT INTO tenants (id,name,slug,created_at,updated_at) VALUES (?,?,?,?,?)').run([id, data.name, data.slug, now, now])\n const row = this.stmt('SELECT * FROM tenants WHERE id = ?').get(id) as RawTenant | null\n if (!row) throw new Error('Failed to create tenant')\n return { id: row.id, name: row.name, slug: row.slug, createdAt: row.created_at, updatedAt: row.updated_at }\n }\n\n async updateTenant(id: string, data: UpdateTenantInput): Promise<Tenant> {\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?']\n const vals: Val[] = [now]\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.slug != null) { fields.push('slug = ?'); vals.push(data.slug) }\n vals.push(id)\n this.stmt(`UPDATE tenants SET ${fields.join(', ')} WHERE id = ?`).run(vals)\n const row = this.stmt('SELECT * FROM tenants WHERE id = ?').get(id) as RawTenant | null\n if (!row) throw new Error(`Tenant ${id} not found`)\n return { id: row.id, name: row.name, slug: row.slug, createdAt: row.created_at, updatedAt: row.updated_at }\n }\n\n async deleteTenant(id: string): Promise<void> {\n this.stmt('DELETE FROM tenants WHERE id = ?').run(id)\n }\n\n async purgeExpiredConsents(olderThanDays: number): Promise<number> {\n const cutoff = new Date(Date.now() - olderThanDays * 86_400_000).toISOString()\n const toDelete = this.stmt(\n 'SELECT visitor_id FROM consent_records WHERE created_at < ?'\n ).all(cutoff) as unknown as { visitor_id: string }[]\n for (const { visitor_id } of toDelete) {\n this.stmt('DELETE FROM consent_history WHERE visitor_id = ?').run(visitor_id)\n this.stmt('DELETE FROM consent_records WHERE visitor_id = ?').run(visitor_id)\n }\n return toDelete.length\n }\n\n // ── API Keys ───────────────────────────────────────────────────────────────\n\n private mapApiKey(r: RawApiKey): ApiKey {\n return { id: r.id, tenantId: r.tenant_id, keyHash: r.key_hash, name: r.name, isActive: r.is_active === 1, createdAt: r.created_at }\n }\n\n async createApiKey(data: CreateApiKeyInput): Promise<ApiKey> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt('INSERT INTO api_keys (id,tenant_id,key_hash,name,created_at) VALUES (?,?,?,?,?)').run([id, data.tenantId, data.keyHash, data.name, now])\n const row = this.stmt('SELECT * FROM api_keys WHERE id = ?').get(id) as RawApiKey | null\n if (!row) throw new Error('Failed to create API key')\n return this.mapApiKey(row)\n }\n\n async getApiKeyByHash(keyHash: string): Promise<ApiKey | null> {\n const row = this.stmt('SELECT * FROM api_keys WHERE key_hash = ? AND is_active = 1').get(keyHash) as RawApiKey | null\n return row ? this.mapApiKey(row) : null\n }\n\n async revokeApiKey(id: string): Promise<void> {\n this.stmt('UPDATE api_keys SET is_active = 0 WHERE id = ?').run(id)\n }\n\n async getApiKeys(tenantId: string): Promise<ApiKey[]> {\n const rows = this.stmt('SELECT * FROM api_keys WHERE tenant_id = ? ORDER BY created_at DESC').all(tenantId) as unknown as RawApiKey[]\n return rows.map(r => this.mapApiKey(r))\n }\n\n // ── Cookie Templates ───────────────────────────────────────────────────────\n\n private mapCookieTemplate(r: RawCookieTemplate): ServerCookieTemplate {\n return { id: r.id, tenantId: r.tenant_id, name: r.name, cookies: JSON.parse(r.cookies_json), createdAt: r.created_at, updatedAt: r.updated_at }\n }\n\n async createCookieTemplate(data: CreateCookieTemplateInput): Promise<ServerCookieTemplate> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt('INSERT INTO cookie_templates (id,tenant_id,name,cookies_json,created_at,updated_at) VALUES (?,?,?,?,?,?)').run([id, data.tenantId, data.name, JSON.stringify(data.cookies), now, now])\n return this.mapCookieTemplate(this.stmt('SELECT * FROM cookie_templates WHERE id = ?').get(id) as unknown as RawCookieTemplate)\n }\n\n async updateCookieTemplate(id: string, data: UpdateCookieTemplateInput): Promise<ServerCookieTemplate> {\n const now = new Date().toISOString()\n if (data.name !== undefined) this.stmt('UPDATE cookie_templates SET name = ?, updated_at = ? WHERE id = ?').run([data.name, now, id])\n if (data.cookies !== undefined) this.stmt('UPDATE cookie_templates SET cookies_json = ?, updated_at = ? WHERE id = ?').run([JSON.stringify(data.cookies), now, id])\n const row = this.stmt('SELECT * FROM cookie_templates WHERE id = ?').get(id) as RawCookieTemplate | null\n if (!row) throw new Error('Cookie template not found')\n return this.mapCookieTemplate(row)\n }\n\n async deleteCookieTemplate(id: string): Promise<void> {\n this.stmt('DELETE FROM cookie_templates WHERE id = ?').run(id)\n }\n\n async getCookieTemplate(id: string): Promise<ServerCookieTemplate | null> {\n const row = this.stmt('SELECT * FROM cookie_templates WHERE id = ?').get(id) as RawCookieTemplate | null\n return row ? this.mapCookieTemplate(row) : null\n }\n\n async getCookieTemplates(tenantId: string): Promise<ServerCookieTemplate[]> {\n const rows = this.stmt('SELECT * FROM cookie_templates WHERE tenant_id = ? ORDER BY name ASC').all(tenantId) as unknown as RawCookieTemplate[]\n return rows.map(r => this.mapCookieTemplate(r))\n }\n\n async copyCookieTemplate(id: string, newName: string): Promise<ServerCookieTemplate> {\n const src = await this.getCookieTemplate(id)\n if (!src) throw new Error('Cookie template not found')\n return this.createCookieTemplate({ tenantId: src.tenantId, name: newName, cookies: src.cookies })\n }\n\n // ── UI Templates ───────────────────────────────────────────────────────────\n\n private mapUITemplate(r: RawUITemplate): ServerUITemplate {\n const s = JSON.parse(r.settings_json) as Omit<ServerUITemplate, 'id' | 'tenantId' | 'name' | 'createdAt' | 'updatedAt'>\n return { id: r.id, tenantId: r.tenant_id, name: r.name, ...s, createdAt: r.created_at, updatedAt: r.updated_at }\n }\n\n async createUITemplate(data: CreateUITemplateInput): Promise<ServerUITemplate> {\n const id = randomUUID()\n const now = new Date().toISOString()\n const { tenantId, name, ...settings } = data\n this.stmt('INSERT INTO ui_templates (id,tenant_id,name,settings_json,created_at,updated_at) VALUES (?,?,?,?,?,?)').run([id, tenantId, name, JSON.stringify(settings), now, now])\n return this.mapUITemplate(this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as unknown as RawUITemplate)\n }\n\n async updateUITemplate(id: string, data: UpdateUITemplateInput): Promise<ServerUITemplate> {\n const now = new Date().toISOString()\n const row = this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as RawUITemplate | null\n if (!row) throw new Error('UI template not found')\n if (data.name !== undefined) this.stmt('UPDATE ui_templates SET name = ?, updated_at = ? WHERE id = ?').run([data.name, now, id])\n const { name: _n, ...settingsUpdate } = data\n if (Object.keys(settingsUpdate).length > 0) {\n const current = JSON.parse(row.settings_json) as Record<string, unknown>\n const merged = { ...current, ...settingsUpdate }\n this.stmt('UPDATE ui_templates SET settings_json = ?, updated_at = ? WHERE id = ?').run([JSON.stringify(merged), now, id])\n }\n return this.mapUITemplate(this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as unknown as RawUITemplate)\n }\n\n async deleteUITemplate(id: string): Promise<void> {\n this.stmt('DELETE FROM ui_templates WHERE id = ?').run(id)\n }\n\n async getUITemplate(id: string): Promise<ServerUITemplate | null> {\n const row = this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as RawUITemplate | null\n return row ? this.mapUITemplate(row) : null\n }\n\n async getUITemplates(tenantId: string): Promise<ServerUITemplate[]> {\n const rows = this.stmt('SELECT * FROM ui_templates WHERE tenant_id = ? ORDER BY name ASC').all(tenantId) as unknown as RawUITemplate[]\n return rows.map(r => this.mapUITemplate(r))\n }\n\n async copyUITemplate(id: string, newName: string): Promise<ServerUITemplate> {\n const src = await this.getUITemplate(id)\n if (!src) throw new Error('UI template not found')\n const { tenantId, mainBanner, gpcBanner, preferenceModal } = src\n return this.createUITemplate({ tenantId, name: newName, mainBanner, gpcBanner, preferenceModal })\n }\n\n // ── Profile summaries ──────────────────────────────────────────────────────\n\n private mapProfileSummary(r: RawProfileSummary): ProfileSummary {\n return {\n id: r.id,\n name: r.name,\n defaultLocale: r.default_locale,\n complianceGroup: (r.compliance_group ?? null) as ComplianceGroupId | null,\n version: r.version,\n isActive: r.is_active === 1,\n cookieTemplateName: r.cookie_template_name,\n uiTemplateName: r.ui_template_name,\n createdAt: r.created_at,\n updatedAt: r.updated_at,\n }\n }\n\n private readonly PROFILE_SUMMARY_SQL = `\n SELECT\n p.id, p.name, p.default_locale, p.version, p.created_at, p.updated_at,\n json_extract(p.profile_json, '$.complianceGroup') AS compliance_group,\n json_extract(p.profile_json, '$.isActive') AS is_active,\n json_extract(p.profile_json, '$.cookieTemplateId') AS cookie_template_id,\n json_extract(p.profile_json, '$.uiTemplateId') AS ui_template_id,\n ct.name AS cookie_template_name,\n ut.name AS ui_template_name\n FROM profiles p\n LEFT JOIN cookie_templates ct ON ct.id = json_extract(p.profile_json, '$.cookieTemplateId')\n LEFT JOIN ui_templates ut ON ut.id = json_extract(p.profile_json, '$.uiTemplateId')\n `\n\n async listProfilesSummary(tenantId: string): Promise<ProfileSummary[]> {\n const rows = this.stmt(\n `${this.PROFILE_SUMMARY_SQL} WHERE p.tenant_id = ? ORDER BY p.created_at ASC`\n ).all(tenantId) as unknown as RawProfileSummary[]\n return rows.map(r => this.mapProfileSummary(r))\n }\n\n async findProfilesUsingCookieTemplate(templateId: string): Promise<ProfileSummary[]> {\n const rows = this.stmt(\n `${this.PROFILE_SUMMARY_SQL} WHERE json_extract(p.profile_json, '$.cookieTemplateId') = ? ORDER BY p.name ASC`\n ).all(templateId) as unknown as RawProfileSummary[]\n return rows.map(r => this.mapProfileSummary(r))\n }\n\n async findProfilesUsingUITemplate(templateId: string): Promise<ProfileSummary[]> {\n const rows = this.stmt(\n `${this.PROFILE_SUMMARY_SQL} WHERE json_extract(p.profile_json, '$.uiTemplateId') = ? ORDER BY p.name ASC`\n ).all(templateId) as unknown as RawProfileSummary[]\n return rows.map(r => this.mapProfileSummary(r))\n }\n\n async getOptInStats(tenantId: string, filters: OptInFilters): Promise<OptInStats> {\n const conditions: string[] = ['cr.tenant_id = ?']\n const vals: Val[] = [tenantId]\n if (filters.profileId) { conditions.push('cr.profile_id = ?'); vals.push(filters.profileId) }\n if (filters.from) { conditions.push('cr.created_at >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('cr.created_at <= ?'); vals.push(filters.to) }\n if (filters.locale) { conditions.push('cr.locale = ?'); vals.push(filters.locale) }\n const where = conditions.join(' AND ')\n\n const rows = this.stmt(\n `SELECT cr.locale, cr.consent_json FROM consent_records cr WHERE ${where}`\n ).all(vals) as unknown as { locale: string; consent_json: string }[]\n\n let total = 0, granted = 0, denied = 0, managed = 0\n const byLocale: Record<string, { total: number; granted: number; denied: number; managed: number }> = {}\n\n for (const r of rows) {\n const statuses = Object.values(JSON.parse(r.consent_json) as Record<string, string>)\n const grantedPct = statuses.length > 0 ? statuses.filter(s => s === 'granted').length / statuses.length : 0\n const deniedPct = statuses.length > 0 ? statuses.filter(s => s === 'denied').length / statuses.length : 0\n total++\n const loc = r.locale\n if (!byLocale[loc]) byLocale[loc] = { total: 0, granted: 0, denied: 0, managed: 0 }\n byLocale[loc]!.total++\n if (grantedPct >= 0.9) { granted++; byLocale[loc]!.granted++ }\n else if (deniedPct >= 0.9) { denied++; byLocale[loc]!.denied++ }\n else { managed++; byLocale[loc]!.managed++ }\n }\n\n const dateRows = this.stmt(\n `SELECT date(cr.created_at) as d, cr.consent_json FROM consent_records cr WHERE ${where} ORDER BY d ASC`\n ).all(vals) as unknown as { d: string; consent_json: string }[]\n\n const dateMap = new Map<string, { total: number; granted: number; denied: number; managed: number }>()\n for (const r of dateRows) {\n const entry = dateMap.get(r.d) ?? { total: 0, granted: 0, denied: 0, managed: 0 }\n const statuses = Object.values(JSON.parse(r.consent_json) as Record<string, string>)\n const grantedPct = statuses.length > 0 ? statuses.filter(s => s === 'granted').length / statuses.length : 0\n const deniedPct = statuses.length > 0 ? statuses.filter(s => s === 'denied').length / statuses.length : 0\n entry.total++\n if (grantedPct >= 0.9) entry.granted++\n else if (deniedPct >= 0.9) entry.denied++\n else entry.managed++\n dateMap.set(r.d, entry)\n }\n\n const byDate = Array.from(dateMap.entries()).map(([date, v]) => ({ date, ...v }))\n return {\n total, granted, denied, managed,\n grantedPct: total > 0 ? Math.round((granted / total) * 1000) / 10 : 0,\n deniedPct: total > 0 ? Math.round((denied / total) * 1000) / 10 : 0,\n managedPct: total > 0 ? Math.round((managed / total) * 1000) / 10 : 0,\n byLocale,\n byDate,\n }\n }\n}\n","import type { DatabaseSync, StatementSync } from 'node:sqlite'\n\nconst MAX_PAGE_SIZE = 500\nimport { randomUUID, randomProfileId } from '../../utils/crypto'\nimport { resolveStoragePaths } from '../../utils/storage-path'\nimport {\n SEED_SQL,\n SCHEMA_SQL_SQLITE,\n SCHEMA_SQL_SQLITE_API_KEYS,\n SCHEMA_SQL_SQLITE_ENTERPRISE,\n SCHEMA_SQL_SQLITE_TEMPLATES,\n} from '../seed-data'\nimport type {\n StorageAdapter,\n StorageConfig,\n Profile,\n ProfileConfig,\n ProfileSummary,\n OptInStats,\n OptInFilters,\n ComplianceGroupId,\n CreateProfileInput,\n UpdateProfileInput,\n ConsentDbRecord,\n ConsentHistoryEntry,\n ConsentValue,\n CreateConsentInput,\n UpdateConsentInput,\n ConsentFilters,\n Visitor,\n VisitorFilters,\n CreateVisitorInput,\n UpdateVisitorInput,\n AdminUser,\n CreateUserInput,\n UpdateUserInput,\n Role,\n CreateRoleInput,\n UpdateRoleInput,\n Permission,\n AuditLog,\n AuditFilters,\n CreateAuditLogInput,\n OverviewStats,\n CategoryStats,\n TimelineEntry,\n CountryStat,\n GpcStats,\n Tenant,\n ApiKey,\n CreateApiKeyInput,\n CreateTenantInput,\n UpdateTenantInput,\n ServerCookieTemplate,\n ServerUITemplate,\n CreateCookieTemplateInput,\n UpdateCookieTemplateInput,\n CreateUITemplateInput,\n UpdateUITemplateInput,\n} from '@consenti/types'\n\ninterface RawProfile {\n id: string; tenant_id: string; name: string; default_locale: string\n version: number; profile_json: string\n created_at: string; updated_at: string\n}\ninterface RawConsent {\n id: string; tenant_id: string; visitor_id: string; profile_id: string\n profile_version: number; locale: string; consent_json: string\n gpc_detected: number; source: string; created_at: string; updated_at: string\n age_verified?: number; parental_consent_token?: string | null; tcf_string?: string | null\n}\ninterface RawConsentHistory {\n id: string; tenant_id: string; consent_record_id: string; visitor_id: string\n old_json: string | null; new_json: string; action: string; created_at: string\n}\ninterface RawVisitor {\n id: string; tenant_id: string; visitor_id: string\n country: string | null; region: string | null; city: string | null\n ip_hash: string | null; user_agent_hash: string | null\n first_seen: string; last_seen: string\n}\ninterface RawUser {\n id: string; tenant_id: string; name: string; email: string\n password_hash: string; is_active: number; created_at: string; updated_at: string\n totp_secret?: string | null; totp_enabled?: number\n allowed_tenants?: string | null\n}\n\ninterface RawProfileSummary {\n id: string; name: string; default_locale: string; version: number\n compliance_group: string | null; is_active: number\n cookie_template_name: string | null; ui_template_name: string | null\n created_at: string; updated_at: string\n cookie_template_id: string | null; ui_template_id: string | null\n}\ninterface RawRole {\n id: string; tenant_id: string; name: string; description: string | null\n}\ninterface RawPermission {\n id: string; name: string; description: string | null\n}\ninterface RawAuditLog {\n id: string; tenant_id: string; user_id: string | null; action: string\n resource_type: string; resource_id: string | null\n old_data: string | null; new_data: string | null; created_at: string\n}\ninterface RawTenant {\n id: string; name: string; slug: string; created_at: string; updated_at: string\n}\ninterface RawApiKey {\n id: string; tenant_id: string; key_hash: string; name: string; is_active: number; created_at: string\n}\ninterface RawCookieTemplate {\n id: string; tenant_id: string; name: string; cookies_json: string; created_at: string; updated_at: string\n}\ninterface RawUITemplate {\n id: string; tenant_id: string; name: string; settings_json: string; created_at: string; updated_at: string\n}\n\n\ntype Stmt = StatementSync\n\nexport class NodeSqliteBuiltinAdapter implements StorageAdapter {\n private db!: DatabaseSync\n private cache = new Map<string, Stmt>()\n\n constructor(private config: StorageConfig) {}\n\n private stmt(sql: string): Stmt {\n let s = this.cache.get(sql)\n if (!s) { s = this.db.prepare(sql); this.cache.set(sql, s) }\n return s\n }\n\n async connect(): Promise<void> {\n // Lazy: node:sqlite is only available on Node.js >= 22.5.0.\n // Loading it here (not at module load) prevents startup failure on Node 20.\n const { DatabaseSync: Db } = await import('node:sqlite').catch(() => {\n throw new Error(`driver 'node:sqlite' requires Node.js >= 22.5.0 (current: ${process.version})`)\n }) as { DatabaseSync: new(path: string) => DatabaseSync }\n const { dbPath } = resolveStoragePaths(this.config.path ?? './consenti-data', 'node:sqlite')\n this.db = new Db(dbPath)\n this.db.exec('PRAGMA journal_mode=WAL')\n this.db.exec('PRAGMA foreign_keys=ON')\n this.db.exec('PRAGMA synchronous=NORMAL')\n await this.migrate()\n }\n\n async disconnect(): Promise<void> {\n this.cache.clear()\n this.db.close()\n }\n\n async migrate(): Promise<void> {\n const row = this.db.prepare('PRAGMA user_version').get() as { user_version: number }\n if (row.user_version < 1) {\n this.db.exec(SCHEMA_SQL_SQLITE)\n this.db.exec(SEED_SQL)\n this.db.exec('PRAGMA user_version = 1')\n }\n if (row.user_version < 2) {\n this.db.exec(SCHEMA_SQL_SQLITE_API_KEYS)\n this.db.exec('PRAGMA user_version = 2')\n }\n if (row.user_version < 3) {\n this.db.exec(SCHEMA_SQL_SQLITE_ENTERPRISE)\n this.db.exec('PRAGMA user_version = 3')\n }\n if (row.user_version < 4) {\n this.db.exec('ALTER TABLE user_roles ADD COLUMN tenant_id TEXT NOT NULL DEFAULT \\'default\\'')\n this.db.exec('PRAGMA user_version = 4')\n }\n if (row.user_version < 5) {\n this.db.exec(SCHEMA_SQL_SQLITE_TEMPLATES)\n this.db.exec('PRAGMA user_version = 5')\n }\n if (row.user_version < 6) {\n this.db.exec('ALTER TABLE users ADD COLUMN allowed_tenants TEXT')\n this.db.exec('PRAGMA user_version = 6')\n }\n\n // Indexes — always idempotent (CREATE INDEX IF NOT EXISTS)\n this.db.exec(`\n CREATE INDEX IF NOT EXISTS idx_profiles_tenant_compliance_active\n ON profiles (tenant_id, json_extract(profile_json,'$.complianceGroup'), json_extract(profile_json,'$.isActive'));\n CREATE INDEX IF NOT EXISTS idx_profiles_tenant\n ON profiles (tenant_id);\n CREATE INDEX IF NOT EXISTS idx_consents_tenant_profile_date\n ON consent_records (tenant_id, profile_id, created_at);\n CREATE INDEX IF NOT EXISTS idx_consents_visitor\n ON consent_records (visitor_id);\n CREATE INDEX IF NOT EXISTS idx_visitors_tenant\n ON visitors (tenant_id);\n CREATE INDEX IF NOT EXISTS idx_audit_tenant_date\n ON audit_logs (tenant_id, created_at);\n `)\n }\n\n // ── Profiles ──────────────────────────────────────────────────────────────\n\n private mapProfile(row: RawProfile): Profile {\n return {\n id: row.id,\n tenantId: row.tenant_id,\n name: row.name,\n defaultLocale: row.default_locale,\n version: row.version,\n profileJson: JSON.parse(row.profile_json) as ProfileConfig,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }\n }\n\n async createProfile(data: CreateProfileInput): Promise<Profile> {\n const id = randomProfileId()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO profiles (id,tenant_id,name,default_locale,profile_json,created_at,updated_at) VALUES (?,?,?,?,?,?,?)'\n ).run(id, data.tenantId, data.name, data.defaultLocale, JSON.stringify(data.profileJson), now, now)\n const profile = await this.getProfile(id)\n if (!profile) throw new Error('Failed to create profile')\n return profile\n }\n\n async updateProfile(id: string, data: UpdateProfileInput): Promise<Profile> {\n const existing = await this.getProfile(id)\n if (!existing) throw new Error(`Profile ${id} not found`)\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?', 'version = version + 1']\n const vals: (string | number | null)[] = [now]\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.defaultLocale != null) { fields.push('default_locale = ?'); vals.push(data.defaultLocale) }\n if (data.profileJson != null) { fields.push('profile_json = ?'); vals.push(JSON.stringify(data.profileJson)) }\n vals.push(id)\n this.stmt(`UPDATE profiles SET ${fields.join(', ')} WHERE id = ?`).run(...vals)\n const updated = await this.getProfile(id)\n if (!updated) throw new Error('Failed to update profile')\n return updated\n }\n\n async deleteProfile(id: string): Promise<void> {\n this.stmt('DELETE FROM profiles WHERE id = ?').run(id)\n }\n\n async getProfile(id: string): Promise<Profile | null> {\n const row = this.stmt('SELECT * FROM profiles WHERE id = ?').get(id) as RawProfile | undefined\n return row ? this.mapProfile(row) : null\n }\n\n async getProfiles(tenantId: string): Promise<Profile[]> {\n const rows = this.stmt('SELECT * FROM profiles WHERE tenant_id = ? ORDER BY created_at ASC').all(tenantId) as unknown as RawProfile[]\n return rows.map(r => this.mapProfile(r))\n }\n\n async findActiveProfileByComplianceGroup(tenantId: string, complianceGroup: string): Promise<Profile | null> {\n const row = this.stmt(\n `SELECT * FROM profiles WHERE tenant_id = ? AND json_extract(profile_json, '$.complianceGroup') = ? AND json_extract(profile_json, '$.isActive') = 1 LIMIT 1`\n ).get(tenantId, complianceGroup) as RawProfile | undefined\n return row ? this.mapProfile(row) : null\n }\n\n // ── Consents ──────────────────────────────────────────────────────────────\n\n private mapConsent(row: RawConsent): ConsentDbRecord {\n return {\n id: row.id,\n tenantId: row.tenant_id,\n visitorId: row.visitor_id,\n profileId: row.profile_id,\n profileVersion: row.profile_version,\n locale: row.locale,\n consentJson: JSON.parse(row.consent_json) as ConsentValue,\n gpcDetected: row.gpc_detected === 1,\n source: row.source as ConsentDbRecord['source'],\n ...(row.age_verified != null && row.age_verified !== 0 ? { ageVerified: true } : {}),\n ...(row.parental_consent_token != null ? { parentalConsentToken: row.parental_consent_token } : {}),\n ...(row.tcf_string != null ? { tcfString: row.tcf_string } : {}),\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }\n }\n\n async createConsent(data: CreateConsentInput): Promise<ConsentDbRecord> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO consent_records (id,tenant_id,visitor_id,profile_id,profile_version,locale,consent_json,gpc_detected,source,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)'\n ).run(id, data.tenantId, data.visitorId, data.profileId, data.profileVersion, data.locale, JSON.stringify(data.consentJson), data.gpcDetected ? 1 : 0, data.source, now, now)\n const histId = randomUUID()\n this.stmt(\n 'INSERT INTO consent_history (id,tenant_id,consent_record_id,visitor_id,old_json,new_json,action,created_at) VALUES (?,?,?,?,?,?,?,?)'\n ).run(histId, data.tenantId, id, data.visitorId, null, JSON.stringify(data.consentJson), 'created', now)\n const record = await this.getConsent(data.visitorId)\n if (!record) throw new Error('Failed to create consent')\n return record\n }\n\n async updateConsent(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord> {\n const existing = await this.getConsent(visitorId)\n if (!existing) throw new Error(`Consent for visitor ${visitorId} not found`)\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?', 'consent_json = ?']\n const vals: (string | number | null)[] = [now, JSON.stringify(data.consentJson)]\n if (data.locale != null) { fields.push('locale = ?'); vals.push(data.locale) }\n if (data.gpcDetected != null) { fields.push('gpc_detected = ?'); vals.push(data.gpcDetected ? 1 : 0) }\n vals.push(visitorId)\n this.stmt(`UPDATE consent_records SET ${fields.join(', ')} WHERE visitor_id = ?`).run(...vals)\n const histId = randomUUID()\n this.stmt(\n 'INSERT INTO consent_history (id,tenant_id,consent_record_id,visitor_id,old_json,new_json,action,created_at) VALUES (?,?,?,?,?,?,?,?)'\n ).run(histId, existing.tenantId, existing.id, visitorId, JSON.stringify(existing.consentJson), JSON.stringify(data.consentJson), 'updated', now)\n const updated = await this.getConsent(visitorId)\n if (!updated) throw new Error('Failed to update consent')\n return updated\n }\n\n async deleteConsent(visitorId: string): Promise<void> {\n this.stmt('DELETE FROM consent_history WHERE visitor_id = ?').run(visitorId)\n this.stmt('DELETE FROM consent_records WHERE visitor_id = ?').run(visitorId)\n }\n\n async getConsent(visitorId: string): Promise<ConsentDbRecord | null> {\n const row = this.stmt('SELECT * FROM consent_records WHERE visitor_id = ?').get(visitorId) as RawConsent | undefined\n return row ? this.mapConsent(row) : null\n }\n\n async getConsents(filters: ConsentFilters): Promise<ConsentDbRecord[]> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: (string | number | null)[] = [filters.tenantId]\n if (filters.profileId) { conditions.push('profile_id = ?'); vals.push(filters.profileId) }\n if (filters.from) { conditions.push('created_at >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('created_at <= ?'); vals.push(filters.to) }\n const limit = Math.min(filters.limit ?? 50, MAX_PAGE_SIZE)\n const offset = ((filters.page ?? 1) - 1) * limit\n vals.push(limit, offset)\n const rows = this.stmt(\n `SELECT * FROM consent_records WHERE ${conditions.join(' AND ')} ORDER BY created_at DESC LIMIT ? OFFSET ?`\n ).all(...vals) as unknown as RawConsent[]\n return rows.map(r => this.mapConsent(r))\n }\n\n async *streamConsents(filters: ConsentFilters): AsyncIterable<ConsentDbRecord> {\n const pageSize = 500\n let offset = 0\n while (true) {\n const rows = this.stmt(\n 'SELECT * FROM consent_records WHERE tenant_id = ? LIMIT ? OFFSET ?'\n ).all(filters.tenantId, pageSize, offset) as unknown as RawConsent[]\n if (rows.length === 0) break\n for (const row of rows) yield this.mapConsent(row)\n offset += pageSize\n }\n }\n\n async getConsentHistory(visitorId: string): Promise<ConsentHistoryEntry[]> {\n const rows = this.stmt(\n 'SELECT * FROM consent_history WHERE visitor_id = ? ORDER BY created_at ASC'\n ).all(visitorId) as unknown as RawConsentHistory[]\n return rows.map(r => ({\n id: r.id,\n tenantId: r.tenant_id,\n consentRecordId: r.consent_record_id,\n visitorId: r.visitor_id,\n oldJson: r.old_json != null ? JSON.parse(r.old_json) as ConsentValue : null,\n newJson: JSON.parse(r.new_json) as ConsentValue,\n action: r.action as ConsentHistoryEntry['action'],\n createdAt: r.created_at,\n }))\n }\n\n // ── Visitors ──────────────────────────────────────────────────────────────\n\n private mapVisitor(row: RawVisitor): Visitor {\n return {\n id: row.id,\n tenantId: row.tenant_id,\n visitorId: row.visitor_id,\n firstSeen: row.first_seen,\n lastSeen: row.last_seen,\n ...(row.country != null ? { country: row.country } : {}),\n ...(row.region != null ? { region: row.region } : {}),\n ...(row.city != null ? { city: row.city } : {}),\n ...(row.ip_hash != null ? { ipHash: row.ip_hash } : {}),\n ...(row.user_agent_hash != null ? { userAgentHash: row.user_agent_hash } : {}),\n }\n }\n\n async createVisitor(data: CreateVisitorInput): Promise<Visitor> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO visitors (id,tenant_id,visitor_id,country,region,city,ip_hash,user_agent_hash,first_seen,last_seen) VALUES (?,?,?,?,?,?,?,?,?,?)'\n ).run(id, data.tenantId, data.visitorId, data.country ?? null, data.region ?? null, data.city ?? null, data.ipHash ?? null, data.userAgentHash ?? null, now, now)\n const visitor = await this.getVisitor(data.visitorId)\n if (!visitor) throw new Error('Failed to create visitor')\n return visitor\n }\n\n async updateVisitor(visitorId: string, data: UpdateVisitorInput): Promise<Visitor> {\n const now = new Date().toISOString()\n const fields: string[] = ['last_seen = ?']\n const vals: (string | number | null)[] = [data.lastSeen ?? now]\n if (data.country != null) { fields.push('country = ?'); vals.push(data.country) }\n if (data.region != null) { fields.push('region = ?'); vals.push(data.region) }\n if (data.city != null) { fields.push('city = ?'); vals.push(data.city) }\n vals.push(visitorId)\n this.stmt(`UPDATE visitors SET ${fields.join(', ')} WHERE visitor_id = ?`).run(...vals)\n const visitor = await this.getVisitor(visitorId)\n if (!visitor) throw new Error(`Visitor ${visitorId} not found`)\n return visitor\n }\n\n async deleteVisitor(visitorId: string): Promise<void> {\n this.stmt('DELETE FROM visitors WHERE visitor_id = ?').run(visitorId)\n }\n\n async getVisitor(visitorId: string): Promise<Visitor | null> {\n const row = this.stmt('SELECT * FROM visitors WHERE visitor_id = ?').get(visitorId) as RawVisitor | undefined\n return row ? this.mapVisitor(row) : null\n }\n\n async getVisitors(filters: VisitorFilters): Promise<Visitor[]> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: (string | number | null)[] = [filters.tenantId]\n if (filters.from) { conditions.push('first_seen >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('first_seen <= ?'); vals.push(filters.to) }\n const limit = Math.min(filters.limit ?? 50, MAX_PAGE_SIZE)\n const offset = ((filters.page ?? 1) - 1) * limit\n vals.push(limit, offset)\n const rows = this.stmt(\n `SELECT * FROM visitors WHERE ${conditions.join(' AND ')} ORDER BY last_seen DESC LIMIT ? OFFSET ?`\n ).all(...vals) as unknown as RawVisitor[]\n return rows.map(r => this.mapVisitor(r))\n }\n\n // ── Users ─────────────────────────────────────────────────────────────────\n\n private mapUser(row: RawUser): AdminUser {\n const allowedTenants: string[] = row.allowed_tenants\n ? JSON.parse(row.allowed_tenants) as string[]\n : []\n return {\n id: row.id,\n tenantId: row.tenant_id,\n name: row.name,\n email: row.email,\n passwordHash: row.password_hash,\n isActive: row.is_active === 1,\n totpEnabled: row.totp_enabled === 1,\n ...(row.totp_secret != null ? { totpSecret: row.totp_secret } : {}),\n allowedTenants,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }\n }\n\n async createUser(data: CreateUserInput): Promise<AdminUser> {\n const id = randomUUID()\n const now = new Date().toISOString()\n const allowedTenantsJson = data.allowedTenants?.length ? JSON.stringify(data.allowedTenants) : null\n this.stmt(\n 'INSERT INTO users (id,tenant_id,name,email,password_hash,allowed_tenants,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?)'\n ).run(id, data.tenantId, data.name, data.email, data.passwordHash, allowedTenantsJson, now, now)\n const user = await this.getUserByEmail(data.email)\n if (!user) throw new Error('Failed to create user')\n return user\n }\n\n async updateUser(id: string, data: UpdateUserInput): Promise<AdminUser> {\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?']\n const vals: (string | number | null)[] = [now]\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.email != null) { fields.push('email = ?'); vals.push(data.email) }\n if (data.passwordHash != null) { fields.push('password_hash = ?'); vals.push(data.passwordHash) }\n if (data.isActive != null) { fields.push('is_active = ?'); vals.push(data.isActive ? 1 : 0) }\n if ('totpSecret' in data) { fields.push('totp_secret = ?'); vals.push(data.totpSecret ?? null) }\n if (data.totpEnabled != null) { fields.push('totp_enabled = ?'); vals.push(data.totpEnabled ? 1 : 0) }\n if ('allowedTenants' in data) {\n fields.push('allowed_tenants = ?')\n vals.push(data.allowedTenants?.length ? JSON.stringify(data.allowedTenants) : null)\n }\n vals.push(id)\n this.stmt(`UPDATE users SET ${fields.join(', ')} WHERE id = ?`).run(...vals)\n const row = this.stmt('SELECT * FROM users WHERE id = ?').get(id) as RawUser | undefined\n if (!row) throw new Error(`User ${id} not found`)\n return this.mapUser(row)\n }\n\n async deleteUser(id: string): Promise<void> {\n this.stmt('DELETE FROM user_roles WHERE user_id = ?').run(id)\n this.stmt('DELETE FROM users WHERE id = ?').run(id)\n }\n\n async getUserById(id: string): Promise<AdminUser | null> {\n const row = this.stmt('SELECT * FROM users WHERE id = ?').get(id) as RawUser | undefined\n return row ? this.mapUser(row) : null\n }\n\n async getUserByEmail(email: string): Promise<AdminUser | null> {\n const row = this.stmt('SELECT * FROM users WHERE email = ?').get(email) as RawUser | undefined\n return row ? this.mapUser(row) : null\n }\n\n async getUsers(tenantId: string): Promise<AdminUser[]> {\n const rows = this.stmt('SELECT * FROM users WHERE tenant_id = ? ORDER BY created_at ASC').all(tenantId) as unknown as RawUser[]\n return rows.map(r => this.mapUser(r))\n }\n\n async countUsers(tenantId?: string): Promise<number> {\n const row = tenantId\n ? this.stmt('SELECT COUNT(*) as n FROM users WHERE tenant_id = ?').get(tenantId) as { n: number } | undefined\n : this.stmt('SELECT COUNT(*) as n FROM users').get() as { n: number } | undefined\n return row?.n ?? 0\n }\n\n // ── Roles & Permissions ───────────────────────────────────────────────────\n\n async getRoles(tenantId: string): Promise<Role[]> {\n const rows = this.stmt('SELECT * FROM roles WHERE tenant_id = ?').all(tenantId) as unknown as RawRole[]\n return rows.map(r => ({\n id: r.id, tenantId: r.tenant_id, name: r.name,\n ...(r.description != null ? { description: r.description } : {}),\n }))\n }\n\n async createRole(data: CreateRoleInput): Promise<Role> {\n const id = randomUUID()\n this.stmt('INSERT INTO roles (id,tenant_id,name,description) VALUES (?,?,?,?)').run(\n id, data.tenantId, data.name, data.description ?? null\n )\n const row = this.stmt('SELECT * FROM roles WHERE id = ?').get(id) as RawRole | undefined\n if (!row) throw new Error('Failed to create role')\n return { id: row.id, tenantId: row.tenant_id, name: row.name, ...(row.description != null ? { description: row.description } : {}) }\n }\n\n async updateRole(id: string, data: UpdateRoleInput): Promise<Role> {\n const fields: string[] = []\n const vals: (string | number | null)[] = []\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.description != null) { fields.push('description = ?'); vals.push(data.description) }\n if (fields.length > 0) {\n vals.push(id)\n this.stmt(`UPDATE roles SET ${fields.join(', ')} WHERE id = ?`).run(...vals)\n }\n const row = this.stmt('SELECT * FROM roles WHERE id = ?').get(id) as RawRole | undefined\n if (!row) throw new Error(`Role ${id} not found`)\n return { id: row.id, tenantId: row.tenant_id, name: row.name, ...(row.description != null ? { description: row.description } : {}) }\n }\n\n async deleteRole(id: string): Promise<void> {\n this.stmt('DELETE FROM role_permissions WHERE role_id = ?').run(id)\n this.stmt('DELETE FROM user_roles WHERE role_id = ?').run(id)\n this.stmt('DELETE FROM roles WHERE id = ?').run(id)\n }\n\n async getAllPermissions(): Promise<Permission[]> {\n const rows = this.stmt('SELECT * FROM permissions ORDER BY name ASC').all() as unknown as RawPermission[]\n return rows.map(r => ({ id: r.id, name: r.name, ...(r.description != null ? { description: r.description } : {}) }))\n }\n\n async assignPermissionToRole(roleId: string, permissionId: string): Promise<void> {\n this.stmt('INSERT OR IGNORE INTO role_permissions (role_id,permission_id) VALUES (?,?)').run(roleId, permissionId)\n }\n\n async revokePermissionFromRole(roleId: string, permissionId: string): Promise<void> {\n this.stmt('DELETE FROM role_permissions WHERE role_id = ? AND permission_id = ?').run(roleId, permissionId)\n }\n\n async getPermissionsForRole(roleId: string): Promise<Permission[]> {\n const rows = this.stmt(\n 'SELECT p.* FROM permissions p JOIN role_permissions rp ON rp.permission_id = p.id WHERE rp.role_id = ?'\n ).all(roleId) as unknown as RawPermission[]\n return rows.map(r => ({\n id: r.id, name: r.name,\n ...(r.description != null ? { description: r.description } : {}),\n }))\n }\n\n async getUserRoles(userId: string, tenantId?: string): Promise<Role[]> {\n const rows = tenantId\n ? this.stmt(\n 'SELECT r.* FROM roles r JOIN user_roles ur ON ur.role_id = r.id WHERE ur.user_id = ? AND ur.tenant_id = ?'\n ).all(userId, tenantId) as unknown as RawRole[]\n : this.stmt(\n 'SELECT r.* FROM roles r JOIN user_roles ur ON ur.role_id = r.id WHERE ur.user_id = ?'\n ).all(userId) as unknown as RawRole[]\n return rows.map(r => ({\n id: r.id, tenantId: r.tenant_id, name: r.name,\n ...(r.description != null ? { description: r.description } : {}),\n }))\n }\n\n async assignRole(userId: string, roleId: string, tenantId = 'default'): Promise<void> {\n this.stmt('INSERT OR IGNORE INTO user_roles (user_id, role_id, tenant_id) VALUES (?,?,?)').run(userId, roleId, tenantId)\n }\n\n async revokeRole(userId: string, roleId: string, tenantId?: string): Promise<void> {\n if (tenantId) {\n this.stmt('DELETE FROM user_roles WHERE user_id = ? AND role_id = ? AND tenant_id = ?').run(userId, roleId, tenantId)\n } else {\n this.stmt('DELETE FROM user_roles WHERE user_id = ? AND role_id = ?').run(userId, roleId)\n }\n }\n\n // ── Audit ─────────────────────────────────────────────────────────────────\n\n async createLog(data: CreateAuditLogInput): Promise<void> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt(\n 'INSERT INTO audit_logs (id,tenant_id,user_id,action,resource_type,resource_id,old_data,new_data,created_at) VALUES (?,?,?,?,?,?,?,?,?)'\n ).run(\n id, data.tenantId, data.userId ?? null, data.action, data.resourceType,\n data.resourceId ?? null,\n data.oldData != null ? JSON.stringify(data.oldData) : null,\n data.newData != null ? JSON.stringify(data.newData) : null,\n now\n )\n }\n\n async getLogs(filters: AuditFilters): Promise<AuditLog[]> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: (string | number | null)[] = [filters.tenantId]\n if (filters.action) { conditions.push('action = ?'); vals.push(filters.action) }\n if (filters.resourceType) { conditions.push('resource_type = ?'); vals.push(filters.resourceType) }\n if (filters.from) { conditions.push('created_at >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('created_at <= ?'); vals.push(filters.to) }\n const limit = Math.min(filters.limit ?? 50, MAX_PAGE_SIZE)\n const offset = ((filters.page ?? 1) - 1) * limit\n vals.push(limit, offset)\n const rows = this.stmt(\n `SELECT * FROM audit_logs WHERE ${conditions.join(' AND ')} ORDER BY created_at DESC LIMIT ? OFFSET ?`\n ).all(...vals) as unknown as RawAuditLog[]\n return rows.map(r => this.mapAuditLog(r))\n }\n\n private mapAuditLog(r: RawAuditLog): AuditLog {\n return {\n id: r.id, tenantId: r.tenant_id, action: r.action,\n resourceType: r.resource_type, createdAt: r.created_at,\n ...(r.user_id != null ? { userId: r.user_id } : {}),\n ...(r.resource_id != null ? { resourceId: r.resource_id } : {}),\n ...(r.old_data != null ? { oldData: JSON.parse(r.old_data) as unknown } : {}),\n ...(r.new_data != null ? { newData: JSON.parse(r.new_data) as unknown } : {}),\n }\n }\n\n async *streamAuditLogs(filters: AuditFilters): AsyncIterable<AuditLog> {\n const conditions: string[] = ['tenant_id = ?']\n const vals: (string | number | null)[] = [filters.tenantId]\n if (filters.action) { conditions.push('action = ?'); vals.push(filters.action) }\n if (filters.from) { conditions.push('created_at >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('created_at <= ?'); vals.push(filters.to) }\n const pageSize = 500\n let offset = 0\n while (true) {\n const rows = this.stmt(\n `SELECT * FROM audit_logs WHERE ${conditions.join(' AND ')} ORDER BY created_at DESC LIMIT ? OFFSET ?`\n ).all(...vals, pageSize, offset) as unknown as RawAuditLog[]\n if (rows.length === 0) break\n for (const row of rows) yield this.mapAuditLog(row)\n offset += pageSize\n }\n }\n\n // ── Stats ──────────────────────────────────────────────────────────────────\n\n async getOverviewStats(tenantId: string): Promise<OverviewStats> {\n const tc = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ?').get(tenantId) as { n: number } | undefined\n const gc = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ? AND gpc_detected = 1').get(tenantId) as { n: number } | undefined\n const vc = this.stmt('SELECT COUNT(*) as n FROM visitors WHERE tenant_id = ?').get(tenantId) as { n: number } | undefined\n const totalConsents = tc?.n ?? 0\n\n const recent = this.stmt(\n 'SELECT consent_json FROM consent_records WHERE tenant_id = ? ORDER BY created_at DESC LIMIT 500'\n ).all(tenantId) as unknown as { consent_json: string }[]\n\n let accepted = 0, rejected = 0\n for (const r of recent) {\n const vals = Object.values(JSON.parse(r.consent_json) as Record<string, string>)\n const grantedPct = vals.length > 0 ? vals.filter(v => v === 'granted').length / vals.length : 0\n if (grantedPct >= 0.8) accepted++\n else if (grantedPct <= 0.2) rejected++\n }\n const sample = recent.length || 1\n\n return {\n totalConsents,\n gpcDetectedCount: gc?.n ?? 0,\n totalVisitors: vc?.n ?? 0,\n acceptedPct: Math.round((accepted / sample) * 100),\n rejectedPct: Math.round((rejected / sample) * 100),\n }\n }\n\n async getCategoryStats(tenantId: string): Promise<CategoryStats> {\n const rows = this.stmt(\n 'SELECT consent_json FROM consent_records WHERE tenant_id = ? LIMIT 5000'\n ).all(tenantId) as unknown as { consent_json: string }[]\n const stats: CategoryStats = {}\n for (const row of rows) {\n const consent = JSON.parse(row.consent_json) as Record<string, string>\n for (const [key, status] of Object.entries(consent)) {\n if (!stats[key]) stats[key] = { granted: 0, denied: 0, objected: 0 }\n if (status === 'granted') stats[key]!.granted++\n else if (status === 'denied') stats[key]!.denied++\n else if (status === 'objected') stats[key]!.objected++\n }\n }\n return stats\n }\n\n async getTimeline(tenantId: string, days = 30): Promise<TimelineEntry[]> {\n const rows = this.stmt(\n `SELECT date(created_at) as date, COUNT(*) as count FROM consent_records WHERE tenant_id = ? AND created_at >= date('now', ?) GROUP BY date(created_at) ORDER BY date ASC`\n ).all(tenantId, `-${days} days`) as unknown as { date: string; count: number }[]\n return rows.map(r => ({ date: r.date, count: r.count }))\n }\n\n async getCountries(tenantId: string): Promise<CountryStat[]> {\n const rows = this.stmt(\n `SELECT v.country, COUNT(*) as count FROM consent_records cr JOIN visitors v ON v.visitor_id = cr.visitor_id WHERE cr.tenant_id = ? AND v.country IS NOT NULL GROUP BY v.country ORDER BY count DESC LIMIT 50`\n ).all(tenantId) as unknown as { country: string; count: number }[]\n return rows.map(r => ({ country: r.country, count: r.count }))\n }\n\n async getGpcStats(tenantId: string): Promise<GpcStats> {\n const total = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ?').get(tenantId) as { n: number } | undefined\n const detected = this.stmt('SELECT COUNT(*) as n FROM consent_records WHERE tenant_id = ? AND gpc_detected = 1').get(tenantId) as { n: number } | undefined\n const t = total?.n ?? 0\n const d = detected?.n ?? 0\n return { detected: d, total: t, rate: t > 0 ? Math.round((d / t) * 100) : 0 }\n }\n\n // ── Tenants ────────────────────────────────────────────────────────────────\n\n async getTenants(): Promise<Tenant[]> {\n const rows = this.stmt('SELECT * FROM tenants ORDER BY name ASC').all() as unknown as RawTenant[]\n return rows.map(r => ({ id: r.id, name: r.name, slug: r.slug, createdAt: r.created_at, updatedAt: r.updated_at }))\n }\n\n async createTenant(data: CreateTenantInput): Promise<Tenant> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt('INSERT INTO tenants (id,name,slug,created_at,updated_at) VALUES (?,?,?,?,?)').run(id, data.name, data.slug, now, now)\n const row = this.stmt('SELECT * FROM tenants WHERE id = ?').get(id) as RawTenant | undefined\n if (!row) throw new Error('Failed to create tenant')\n return { id: row.id, name: row.name, slug: row.slug, createdAt: row.created_at, updatedAt: row.updated_at }\n }\n\n async updateTenant(id: string, data: UpdateTenantInput): Promise<Tenant> {\n const now = new Date().toISOString()\n const fields: string[] = ['updated_at = ?']\n const vals: (string | number)[] = [now]\n if (data.name != null) { fields.push('name = ?'); vals.push(data.name) }\n if (data.slug != null) { fields.push('slug = ?'); vals.push(data.slug) }\n vals.push(id)\n this.stmt(`UPDATE tenants SET ${fields.join(', ')} WHERE id = ?`).run(...vals)\n const row = this.stmt('SELECT * FROM tenants WHERE id = ?').get(id) as RawTenant | undefined\n if (!row) throw new Error(`Tenant ${id} not found`)\n return { id: row.id, name: row.name, slug: row.slug, createdAt: row.created_at, updatedAt: row.updated_at }\n }\n\n async deleteTenant(id: string): Promise<void> {\n this.stmt('DELETE FROM tenants WHERE id = ?').run(id)\n }\n\n async purgeExpiredConsents(olderThanDays: number): Promise<number> {\n const cutoff = new Date(Date.now() - olderThanDays * 86_400_000).toISOString()\n const toDelete = this.stmt(\n 'SELECT visitor_id FROM consent_records WHERE created_at < ?'\n ).all(cutoff) as unknown as { visitor_id: string }[]\n for (const { visitor_id } of toDelete) {\n this.stmt('DELETE FROM consent_history WHERE visitor_id = ?').run(visitor_id)\n this.stmt('DELETE FROM consent_records WHERE visitor_id = ?').run(visitor_id)\n }\n return toDelete.length\n }\n\n // ── API Keys ───────────────────────────────────────────────────────────────\n\n private mapApiKey(r: RawApiKey): ApiKey {\n return { id: r.id, tenantId: r.tenant_id, keyHash: r.key_hash, name: r.name, isActive: r.is_active === 1, createdAt: r.created_at }\n }\n\n async createApiKey(data: CreateApiKeyInput): Promise<ApiKey> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt('INSERT INTO api_keys (id,tenant_id,key_hash,name,created_at) VALUES (?,?,?,?,?)').run(id, data.tenantId, data.keyHash, data.name, now)\n const row = this.stmt('SELECT * FROM api_keys WHERE id = ?').get(id) as RawApiKey | undefined\n if (!row) throw new Error('Failed to create API key')\n return this.mapApiKey(row)\n }\n\n async getApiKeyByHash(keyHash: string): Promise<ApiKey | null> {\n const row = this.stmt('SELECT * FROM api_keys WHERE key_hash = ? AND is_active = 1').get(keyHash) as RawApiKey | undefined\n return row ? this.mapApiKey(row) : null\n }\n\n async revokeApiKey(id: string): Promise<void> {\n this.stmt('UPDATE api_keys SET is_active = 0 WHERE id = ?').run(id)\n }\n\n async getApiKeys(tenantId: string): Promise<ApiKey[]> {\n const rows = this.stmt('SELECT * FROM api_keys WHERE tenant_id = ? ORDER BY created_at DESC').all(tenantId) as unknown as RawApiKey[]\n return rows.map(r => this.mapApiKey(r))\n }\n\n // ── Cookie Templates ───────────────────────────────────────────────────────\n\n private mapCookieTemplate(r: RawCookieTemplate): ServerCookieTemplate {\n return { id: r.id, tenantId: r.tenant_id, name: r.name, cookies: JSON.parse(r.cookies_json), createdAt: r.created_at, updatedAt: r.updated_at }\n }\n\n async createCookieTemplate(data: CreateCookieTemplateInput): Promise<ServerCookieTemplate> {\n const id = randomUUID()\n const now = new Date().toISOString()\n this.stmt('INSERT INTO cookie_templates (id,tenant_id,name,cookies_json,created_at,updated_at) VALUES (?,?,?,?,?,?)').run(id, data.tenantId, data.name, JSON.stringify(data.cookies), now, now)\n return this.mapCookieTemplate(this.stmt('SELECT * FROM cookie_templates WHERE id = ?').get(id) as unknown as RawCookieTemplate)\n }\n\n async updateCookieTemplate(id: string, data: UpdateCookieTemplateInput): Promise<ServerCookieTemplate> {\n const now = new Date().toISOString()\n if (data.name !== undefined) this.stmt('UPDATE cookie_templates SET name = ?, updated_at = ? WHERE id = ?').run(data.name, now, id)\n if (data.cookies !== undefined) this.stmt('UPDATE cookie_templates SET cookies_json = ?, updated_at = ? WHERE id = ?').run(JSON.stringify(data.cookies), now, id)\n const row = this.stmt('SELECT * FROM cookie_templates WHERE id = ?').get(id) as RawCookieTemplate | undefined\n if (!row) throw new Error('Cookie template not found')\n return this.mapCookieTemplate(row)\n }\n\n async deleteCookieTemplate(id: string): Promise<void> {\n this.stmt('DELETE FROM cookie_templates WHERE id = ?').run(id)\n }\n\n async getCookieTemplate(id: string): Promise<ServerCookieTemplate | null> {\n const row = this.stmt('SELECT * FROM cookie_templates WHERE id = ?').get(id) as RawCookieTemplate | undefined\n return row ? this.mapCookieTemplate(row) : null\n }\n\n async getCookieTemplates(tenantId: string): Promise<ServerCookieTemplate[]> {\n const rows = this.stmt('SELECT * FROM cookie_templates WHERE tenant_id = ? ORDER BY name ASC').all(tenantId) as unknown as RawCookieTemplate[]\n return rows.map(r => this.mapCookieTemplate(r))\n }\n\n async copyCookieTemplate(id: string, newName: string): Promise<ServerCookieTemplate> {\n const src = await this.getCookieTemplate(id)\n if (!src) throw new Error('Cookie template not found')\n return this.createCookieTemplate({ tenantId: src.tenantId, name: newName, cookies: src.cookies })\n }\n\n // ── UI Templates ───────────────────────────────────────────────────────────\n\n private mapUITemplate(r: RawUITemplate): ServerUITemplate {\n const s = JSON.parse(r.settings_json) as Omit<ServerUITemplate, 'id' | 'tenantId' | 'name' | 'createdAt' | 'updatedAt'>\n return { id: r.id, tenantId: r.tenant_id, name: r.name, ...s, createdAt: r.created_at, updatedAt: r.updated_at }\n }\n\n async createUITemplate(data: CreateUITemplateInput): Promise<ServerUITemplate> {\n const id = randomUUID()\n const now = new Date().toISOString()\n const { tenantId, name, ...settings } = data\n this.stmt('INSERT INTO ui_templates (id,tenant_id,name,settings_json,created_at,updated_at) VALUES (?,?,?,?,?,?)').run(id, tenantId, name, JSON.stringify(settings), now, now)\n return this.mapUITemplate(this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as unknown as RawUITemplate)\n }\n\n async updateUITemplate(id: string, data: UpdateUITemplateInput): Promise<ServerUITemplate> {\n const now = new Date().toISOString()\n const row = this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as RawUITemplate | undefined\n if (!row) throw new Error('UI template not found')\n if (data.name !== undefined) this.stmt('UPDATE ui_templates SET name = ?, updated_at = ? WHERE id = ?').run(data.name, now, id)\n const { name: _n, ...settingsUpdate } = data\n if (Object.keys(settingsUpdate).length > 0) {\n const current = JSON.parse(row.settings_json) as Record<string, unknown>\n const merged = { ...current, ...settingsUpdate }\n this.stmt('UPDATE ui_templates SET settings_json = ?, updated_at = ? WHERE id = ?').run(JSON.stringify(merged), now, id)\n }\n return this.mapUITemplate(this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as unknown as RawUITemplate)\n }\n\n async deleteUITemplate(id: string): Promise<void> {\n this.stmt('DELETE FROM ui_templates WHERE id = ?').run(id)\n }\n\n async getUITemplate(id: string): Promise<ServerUITemplate | null> {\n const row = this.stmt('SELECT * FROM ui_templates WHERE id = ?').get(id) as RawUITemplate | undefined\n return row ? this.mapUITemplate(row) : null\n }\n\n async getUITemplates(tenantId: string): Promise<ServerUITemplate[]> {\n const rows = this.stmt('SELECT * FROM ui_templates WHERE tenant_id = ? ORDER BY name ASC').all(tenantId) as unknown as RawUITemplate[]\n return rows.map(r => this.mapUITemplate(r))\n }\n\n async copyUITemplate(id: string, newName: string): Promise<ServerUITemplate> {\n const src = await this.getUITemplate(id)\n if (!src) throw new Error('UI template not found')\n const { tenantId, mainBanner, gpcBanner, preferenceModal } = src\n return this.createUITemplate({ tenantId, name: newName, mainBanner, gpcBanner, preferenceModal })\n }\n\n // ── Profile summaries ──────────────────────────────────────────────────────\n\n private mapProfileSummary(r: RawProfileSummary): ProfileSummary {\n return {\n id: r.id,\n name: r.name,\n defaultLocale: r.default_locale,\n complianceGroup: (r.compliance_group ?? null) as ComplianceGroupId | null,\n version: r.version,\n isActive: r.is_active === 1,\n cookieTemplateName: r.cookie_template_name,\n uiTemplateName: r.ui_template_name,\n createdAt: r.created_at,\n updatedAt: r.updated_at,\n }\n }\n\n private readonly PROFILE_SUMMARY_SQL = `\n SELECT\n p.id, p.name, p.default_locale, p.version, p.created_at, p.updated_at,\n json_extract(p.profile_json, '$.complianceGroup') AS compliance_group,\n json_extract(p.profile_json, '$.isActive') AS is_active,\n json_extract(p.profile_json, '$.cookieTemplateId') AS cookie_template_id,\n json_extract(p.profile_json, '$.uiTemplateId') AS ui_template_id,\n ct.name AS cookie_template_name,\n ut.name AS ui_template_name\n FROM profiles p\n LEFT JOIN cookie_templates ct ON ct.id = json_extract(p.profile_json, '$.cookieTemplateId')\n LEFT JOIN ui_templates ut ON ut.id = json_extract(p.profile_json, '$.uiTemplateId')\n `\n\n async listProfilesSummary(tenantId: string): Promise<ProfileSummary[]> {\n const rows = this.stmt(\n `${this.PROFILE_SUMMARY_SQL} WHERE p.tenant_id = ? ORDER BY p.created_at ASC`\n ).all(tenantId) as unknown as RawProfileSummary[]\n return rows.map(r => this.mapProfileSummary(r))\n }\n\n async findProfilesUsingCookieTemplate(templateId: string): Promise<ProfileSummary[]> {\n const rows = this.stmt(\n `${this.PROFILE_SUMMARY_SQL} WHERE json_extract(p.profile_json, '$.cookieTemplateId') = ? ORDER BY p.name ASC`\n ).all(templateId) as unknown as RawProfileSummary[]\n return rows.map(r => this.mapProfileSummary(r))\n }\n\n async findProfilesUsingUITemplate(templateId: string): Promise<ProfileSummary[]> {\n const rows = this.stmt(\n `${this.PROFILE_SUMMARY_SQL} WHERE json_extract(p.profile_json, '$.uiTemplateId') = ? ORDER BY p.name ASC`\n ).all(templateId) as unknown as RawProfileSummary[]\n return rows.map(r => this.mapProfileSummary(r))\n }\n\n // ── Analytics ──────────────────────────────────────────────────────────────\n\n async getOptInStats(tenantId: string, filters: OptInFilters): Promise<OptInStats> {\n const conditions: string[] = ['cr.tenant_id = ?']\n const vals: (string | number | null)[] = [tenantId]\n if (filters.profileId) { conditions.push('cr.profile_id = ?'); vals.push(filters.profileId) }\n if (filters.from) { conditions.push('cr.created_at >= ?'); vals.push(filters.from) }\n if (filters.to) { conditions.push('cr.created_at <= ?'); vals.push(filters.to) }\n if (filters.locale) { conditions.push('cr.locale = ?'); vals.push(filters.locale) }\n\n const where = conditions.join(' AND ')\n\n const rows = this.stmt(\n `SELECT cr.locale, cr.consent_json FROM consent_records cr WHERE ${where}`\n ).all(...vals) as unknown as { locale: string; consent_json: string }[]\n\n let total = 0, granted = 0, denied = 0, managed = 0\n const byLocale: Record<string, { total: number; granted: number; denied: number; managed: number }> = {}\n\n for (const r of rows) {\n const consent = JSON.parse(r.consent_json) as Record<string, string>\n const statuses = Object.values(consent)\n const grantedCount = statuses.filter(s => s === 'granted').length\n const deniedCount = statuses.filter(s => s === 'denied').length\n const grantedPct = statuses.length > 0 ? grantedCount / statuses.length : 0\n\n total++\n const loc = r.locale\n if (!byLocale[loc]) byLocale[loc] = { total: 0, granted: 0, denied: 0, managed: 0 }\n byLocale[loc]!.total++\n\n if (grantedPct >= 0.9) { granted++; byLocale[loc]!.granted++ }\n else if (deniedCount / (statuses.length || 1) >= 0.9) { denied++; byLocale[loc]!.denied++ }\n else { managed++; byLocale[loc]!.managed++ }\n }\n\n // byDate — aggregate by date(created_at)\n const dateRows = this.stmt(\n `SELECT date(cr.created_at) as d, cr.consent_json FROM consent_records cr WHERE ${where} ORDER BY d ASC`\n ).all(...vals) as unknown as { d: string; consent_json: string }[]\n\n const dateMap = new Map<string, { total: number; granted: number; denied: number; managed: number }>()\n for (const r of dateRows) {\n const entry = dateMap.get(r.d) ?? { total: 0, granted: 0, denied: 0, managed: 0 }\n const consent = JSON.parse(r.consent_json) as Record<string, string>\n const statuses = Object.values(consent)\n const grantedPct = statuses.length > 0 ? statuses.filter(s => s === 'granted').length / statuses.length : 0\n const deniedPct = statuses.length > 0 ? statuses.filter(s => s === 'denied').length / statuses.length : 0\n entry.total++\n if (grantedPct >= 0.9) entry.granted++\n else if (deniedPct >= 0.9) entry.denied++\n else entry.managed++\n dateMap.set(r.d, entry)\n }\n\n const byDate = Array.from(dateMap.entries()).map(([date, v]) => ({ date, ...v }))\n\n return {\n total, granted, denied, managed,\n grantedPct: total > 0 ? Math.round((granted / total) * 1000) / 10 : 0,\n deniedPct: total > 0 ? Math.round((denied / total) * 1000) / 10 : 0,\n managedPct: total > 0 ? Math.round((managed / total) * 1000) / 10 : 0,\n byLocale,\n byDate,\n }\n }\n}\n","import type { MongoClient, Db } from 'mongodb'\nimport { randomUUID } from '../../utils/crypto'\nimport { SEED_TENANT, SEED_PERMISSIONS, SEED_ROLES, SEED_ROLE_PERMISSIONS } from '../seed-data'\nimport type {\n StorageAdapter, StorageConfig, Profile, ProfileConfig,\n CreateProfileInput, UpdateProfileInput,\n ConsentDbRecord, ConsentHistoryEntry, ConsentValue, ConsentFilters,\n CreateConsentInput, UpdateConsentInput,\n Visitor, VisitorFilters, CreateVisitorInput, UpdateVisitorInput,\n AdminUser, CreateUserInput, UpdateUserInput,\n Role, CreateRoleInput, UpdateRoleInput,\n Permission, AuditLog, AuditFilters, CreateAuditLogInput,\n OverviewStats, CategoryStats, TimelineEntry,\n CountryStat, GpcStats, Tenant, ApiKey, CreateApiKeyInput,\n CreateTenantInput, UpdateTenantInput,\n} from '@consenti/types'\n\n// ── Raw document shapes ────────────────────────────────────────────────────────\n\ninterface DocProfile {\n _id: string; tenant_id: string; name: string; default_locale: string\n version: number; profile_json: ProfileConfig\n created_at: string; updated_at: string\n}\ninterface DocConsent {\n _id: string; tenant_id: string; visitor_id: string; profile_id: string\n profile_version: number; locale: string; consent_json: ConsentValue\n gpc_detected: boolean; source: string; created_at: string; updated_at: string\n}\ninterface DocConsentHistory {\n _id: string; tenant_id: string; consent_record_id: string; visitor_id: string\n old_json: ConsentValue | null; new_json: ConsentValue; action: string; created_at: string\n}\ninterface DocVisitor {\n _id: string; tenant_id: string; visitor_id: string\n country?: string; region?: string; city?: string\n ip_hash?: string; user_agent_hash?: string\n first_seen: string; last_seen: string\n}\ninterface DocUser {\n _id: string; tenant_id: string; name: string; email: string\n password_hash: string; is_active: boolean; created_at: string; updated_at: string\n}\ninterface DocRole { _id: string; tenant_id: string; name: string; description?: string }\ninterface DocPermission { _id: string; name: string; description?: string }\ninterface DocUserRole { user_id: string; role_id: string; tenant_id?: string }\ninterface DocRolePermission { role_id: string; permission_id: string }\ninterface DocAuditLog {\n _id: string; tenant_id: string; user_id?: string; action: string\n resource_type: string; resource_id?: string\n old_data?: unknown; new_data?: unknown; created_at: string\n}\ninterface DocApiKey {\n _id: string; tenant_id: string; key_hash: string; name: string; is_active: boolean; created_at: string\n}\n\n// ── Mapper helpers ─────────────────────────────────────────────────────────────\n\nfunction cast<T extends object>(doc: object | null): T | null {\n return doc as T | null\n}\n\nfunction castArr<T extends object>(docs: object[]): T[] {\n return docs as T[]\n}\n\nfunction mapProfile(d: DocProfile): Profile {\n return {\n id: d._id, tenantId: d.tenant_id, name: d.name,\n defaultLocale: d.default_locale, version: d.version,\n profileJson: d.profile_json, createdAt: d.created_at, updatedAt: d.updated_at,\n }\n}\n\nfunction mapConsent(d: DocConsent): ConsentDbRecord {\n return {\n id: d._id, tenantId: d.tenant_id, visitorId: d.visitor_id, profileId: d.profile_id,\n profileVersion: d.profile_version, locale: d.locale, consentJson: d.consent_json,\n gpcDetected: d.gpc_detected, source: d.source as ConsentDbRecord['source'],\n createdAt: d.created_at, updatedAt: d.updated_at,\n }\n}\n\nfunction mapHistory(d: DocConsentHistory): ConsentHistoryEntry {\n return {\n id: d._id, tenantId: d.tenant_id, consentRecordId: d.consent_record_id,\n visitorId: d.visitor_id, oldJson: d.old_json, newJson: d.new_json,\n action: d.action as ConsentHistoryEntry['action'], createdAt: d.created_at,\n }\n}\n\nfunction mapVisitor(d: DocVisitor): Visitor {\n return {\n id: d._id, tenantId: d.tenant_id, visitorId: d.visitor_id,\n ...(d.country != null ? { country: d.country } : {}),\n ...(d.region != null ? { region: d.region } : {}),\n ...(d.city != null ? { city: d.city } : {}),\n ...(d.ip_hash != null ? { ipHash: d.ip_hash } : {}),\n ...(d.user_agent_hash != null ? { userAgentHash: d.user_agent_hash } : {}),\n firstSeen: d.first_seen, lastSeen: d.last_seen,\n }\n}\n\nfunction mapUser(d: DocUser): AdminUser {\n return {\n id: d._id, tenantId: d.tenant_id, name: d.name, email: d.email,\n passwordHash: d.password_hash, isActive: d.is_active,\n createdAt: d.created_at, updatedAt: d.updated_at,\n }\n}\n\nfunction mapRole(d: DocRole): Role {\n return {\n id: d._id, tenantId: d.tenant_id, name: d.name,\n ...(d.description != null ? { description: d.description } : {}),\n }\n}\n\nfunction mapPermission(d: DocPermission): Permission {\n return {\n id: d._id, name: d.name,\n ...(d.description != null ? { description: d.description } : {}),\n }\n}\n\nfunction mapAuditLog(d: DocAuditLog): AuditLog {\n return {\n id: d._id, tenantId: d.tenant_id, action: d.action, resourceType: d.resource_type,\n ...(d.user_id != null ? { userId: d.user_id } : {}),\n ...(d.resource_id != null ? { resourceId: d.resource_id } : {}),\n ...(d.old_data != null ? { oldData: d.old_data } : {}),\n ...(d.new_data != null ? { newData: d.new_data } : {}),\n createdAt: d.created_at,\n }\n}\n\n// ── Adapter ────────────────────────────────────────────────────────────────────\n\n// Custom thin wrappers so MongoDB's ObjectId generics don't interfere with our string _id.\n// DocCursor extends AsyncIterable so it supports `for await...of` iteration.\ninterface DocCursor extends AsyncIterable<object> {\n sort(s: object): DocCursor\n skip(n: number): DocCursor\n limit(n: number): DocCursor\n toArray(): Promise<object[]>\n}\ninterface DocCollection {\n insertOne(doc: object): Promise<object>\n findOne(filter: object): Promise<object | null>\n findOneAndUpdate(filter: object, update: object, options?: object): Promise<object | null>\n find(filter: object): DocCursor\n updateOne(filter: object, update: object, options?: object): Promise<object>\n deleteOne(filter: object): Promise<object>\n deleteMany(filter: object): Promise<object>\n countDocuments(filter?: object): Promise<number>\n createIndex(spec: object, options?: object): Promise<object>\n aggregate(pipeline: object[]): { toArray(): Promise<object[]> }\n}\n\nexport class MongoDBAdapter implements StorageAdapter {\n private client!: MongoClient\n private db!: Db\n\n constructor(private config: StorageConfig) { }\n\n private col(name: string): DocCollection {\n // MongoDB's Collection generics assume ObjectId for _id; we use string UUIDs throughout.\n // The cast via unknown is the TypeScript-sanctioned way to bridge structurally incompatible types.\n return this.db.collection(name) as unknown as DocCollection\n }\n\n async connect(): Promise<void> {\n const { MongoClient: MC } = (await import('mongodb')) as { MongoClient: typeof MongoClient }\n const uri = this.config.uri ?? 'mongodb://localhost:27017'\n this.client = new MC(uri)\n await this.client.connect()\n this.db = this.client.db(this.config.database ?? 'consenti')\n await this.migrate()\n }\n\n async disconnect(): Promise<void> {\n await this.client.close()\n }\n\n async migrate(): Promise<void> {\n await this.createIndexes()\n await this.seed()\n }\n\n private async createIndexes(): Promise<void> {\n await this.col('consent_records').createIndex({ visitor_id: 1, profile_id: 1 }, { unique: true })\n await this.col('consent_records').createIndex({ tenant_id: 1 })\n await this.col('consent_records').createIndex({ created_at: 1 })\n await this.col('visitors').createIndex({ visitor_id: 1 }, { unique: true })\n await this.col('visitors').createIndex({ tenant_id: 1 })\n await this.col('users').createIndex({ email: 1 }, { unique: true })\n await this.col('audit_logs').createIndex({ tenant_id: 1, created_at: 1 })\n await this.col('user_roles').createIndex({ user_id: 1 })\n await this.col('role_permissions').createIndex({ role_id: 1 })\n }\n\n private async seed(): Promise<void> {\n const { id, name, slug } = SEED_TENANT\n if (!(await this.col('tenants').findOne({ _id: id }))) {\n await this.col('tenants').insertOne({ _id: id, name, slug })\n }\n for (const p of SEED_PERMISSIONS) {\n const doc = { _id: p.id, name: p.name, description: p.description }\n await this.col('permissions').updateOne({ _id: p.id }, { $setOnInsert: doc }, { upsert: true })\n }\n for (const r of SEED_ROLES) {\n const doc = { _id: r.id, tenant_id: r.tenantId, name: r.name, description: r.description }\n await this.col('roles').updateOne({ _id: r.id }, { $setOnInsert: doc }, { upsert: true })\n }\n const rp = this.col('role_permissions')\n for (const { roleId, permissionId } of SEED_ROLE_PERMISSIONS) {\n await rp.updateOne(\n { role_id: roleId, permission_id: permissionId },\n { $setOnInsert: { role_id: roleId, permission_id: permissionId } },\n { upsert: true },\n )\n }\n }\n\n // ── Profiles ─────────────────────────────────────────────────────────────────\n\n async createProfile(data: CreateProfileInput): Promise<Profile> {\n const now = new Date().toISOString()\n const doc: DocProfile = {\n _id: randomUUID(), tenant_id: data.tenantId, name: data.name,\n default_locale: data.defaultLocale, version: 1,\n profile_json: data.profileJson,\n created_at: now, updated_at: now,\n }\n await this.col('profiles').insertOne(doc)\n return mapProfile(doc)\n }\n\n async updateProfile(id: string, data: UpdateProfileInput): Promise<Profile> {\n const now = new Date().toISOString()\n const set: Record<string, unknown> = { updated_at: now }\n if (data.name != null) set['name'] = data.name\n if (data.defaultLocale != null) set['default_locale'] = data.defaultLocale\n if (data.profileJson != null) set['profile_json'] = data.profileJson\n const res = cast<DocProfile>(await this.col('profiles').findOneAndUpdate(\n { _id: id }, { $set: set, $inc: { version: 1 } }, { returnDocument: 'after' },\n ))\n if (!res) throw new Error(`Profile ${id} not found`)\n return mapProfile(res)\n }\n\n async deleteProfile(id: string): Promise<void> {\n await this.col('profiles').deleteOne({ _id: id })\n }\n\n async getProfile(id: string): Promise<Profile | null> {\n const doc = cast<DocProfile>(await this.col('profiles').findOne({ _id: id }))\n return doc ? mapProfile(doc) : null\n }\n\n async getProfiles(tenantId: string): Promise<Profile[]> {\n const docs = castArr<DocProfile>(await this.col('profiles').find({ tenant_id: tenantId }).toArray())\n return docs.map(mapProfile)\n }\n\n async findActiveProfileByComplianceGroup(tenantId: string, complianceGroup: string): Promise<Profile | null> {\n const profiles = await this.getProfiles(tenantId)\n return profiles.find(p => p.profileJson.complianceGroup === complianceGroup && p.profileJson.isActive) ?? null\n }\n\n // ── Consents ─────────────────────────────────────────────────────────────────\n\n async createConsent(data: CreateConsentInput): Promise<ConsentDbRecord> {\n const now = new Date().toISOString()\n const doc: DocConsent = {\n _id: randomUUID(), tenant_id: data.tenantId, visitor_id: data.visitorId,\n profile_id: data.profileId, profile_version: data.profileVersion,\n locale: data.locale, consent_json: data.consentJson,\n gpc_detected: data.gpcDetected, source: data.source,\n created_at: now, updated_at: now,\n }\n await this.col('consent_records').insertOne(doc)\n await this.writeHistory(doc._id, data.tenantId, data.visitorId, null, data.consentJson, 'created')\n return mapConsent(doc)\n }\n\n async updateConsent(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord> {\n const existing = await this.getConsent(visitorId)\n if (!existing) throw new Error(`Consent for visitor ${visitorId} not found`)\n const now = new Date().toISOString()\n const set: Record<string, unknown> = { updated_at: now, consent_json: data.consentJson }\n if (data.locale != null) set['locale'] = data.locale\n if (data.gpcDetected != null) set['gpc_detected'] = data.gpcDetected\n const res = cast<DocConsent>(await this.col('consent_records').findOneAndUpdate(\n { visitor_id: visitorId }, { $set: set }, { returnDocument: 'after' },\n ))\n if (!res) throw new Error(`Consent for visitor ${visitorId} not found`)\n await this.writeHistory(res._id, res.tenant_id, visitorId, existing.consentJson, data.consentJson, 'updated')\n return mapConsent(res)\n }\n\n async deleteConsent(visitorId: string): Promise<void> {\n await this.col('consent_history').deleteMany({ visitor_id: visitorId })\n await this.col('consent_records').deleteOne({ visitor_id: visitorId })\n }\n\n async getConsent(visitorId: string): Promise<ConsentDbRecord | null> {\n const doc = cast<DocConsent>(await this.col('consent_records').findOne({ visitor_id: visitorId }))\n return doc ? mapConsent(doc) : null\n }\n\n async getConsents(filters: ConsentFilters): Promise<ConsentDbRecord[]> {\n const q = this.buildConsentFilter(filters)\n const page = filters.page ?? 1\n const limit = filters.limit ?? 50\n const docs = castArr<DocConsent>(\n await this.col('consent_records').find(q).sort({ created_at: -1 }).skip((page - 1) * limit).limit(limit).toArray(),\n )\n return docs.map(mapConsent)\n }\n\n async *streamConsents(filters: ConsentFilters): AsyncIterable<ConsentDbRecord> {\n const q = this.buildConsentFilter(filters)\n const cursor = this.col('consent_records').find(q).sort({ created_at: 1 })\n for await (const doc of cursor) yield mapConsent(doc as unknown as DocConsent)\n }\n\n private buildConsentFilter(f: ConsentFilters): Record<string, unknown> {\n const q: Record<string, unknown> = { tenant_id: f.tenantId }\n if (f.profileId != null) q['profile_id'] = f.profileId\n if (f.from != null || f.to != null) {\n const range: Record<string, string> = {}\n if (f.from != null) range['$gte'] = f.from\n if (f.to != null) range['$lte'] = f.to\n q['created_at'] = range\n }\n return q\n }\n\n private async writeHistory(\n consentRecordId: string, tenantId: string, visitorId: string,\n oldJson: ConsentValue | null, newJson: ConsentValue, action: string,\n ): Promise<void> {\n const doc: DocConsentHistory = {\n _id: randomUUID(), tenant_id: tenantId, consent_record_id: consentRecordId,\n visitor_id: visitorId, old_json: oldJson, new_json: newJson,\n action, created_at: new Date().toISOString(),\n }\n await this.col('consent_history').insertOne(doc)\n }\n\n async getConsentHistory(visitorId: string): Promise<ConsentHistoryEntry[]> {\n const docs = castArr<DocConsentHistory>(\n await this.col('consent_history').find({ visitor_id: visitorId }).sort({ created_at: 1 }).toArray(),\n )\n return docs.map(mapHistory)\n }\n\n // ── Visitors ─────────────────────────────────────────────────────────────────\n\n async createVisitor(data: CreateVisitorInput): Promise<Visitor> {\n const now = new Date().toISOString()\n const doc: DocVisitor = {\n _id: randomUUID(), tenant_id: data.tenantId, visitor_id: data.visitorId,\n first_seen: now, last_seen: now,\n ...(data.country != null ? { country: data.country } : {}),\n ...(data.region != null ? { region: data.region } : {}),\n ...(data.city != null ? { city: data.city } : {}),\n ...(data.ipHash != null ? { ip_hash: data.ipHash } : {}),\n ...(data.userAgentHash != null ? { user_agent_hash: data.userAgentHash } : {}),\n }\n await this.col('visitors').insertOne(doc)\n return mapVisitor(doc)\n }\n\n async updateVisitor(visitorId: string, data: UpdateVisitorInput): Promise<Visitor> {\n const set: Record<string, string> = { last_seen: data.lastSeen ?? new Date().toISOString() }\n if (data.country != null) set['country'] = data.country\n if (data.region != null) set['region'] = data.region\n if (data.city != null) set['city'] = data.city\n const res = cast<DocVisitor>(await this.col('visitors').findOneAndUpdate(\n { visitor_id: visitorId }, { $set: set }, { returnDocument: 'after' },\n ))\n if (!res) throw new Error(`Visitor ${visitorId} not found`)\n return mapVisitor(res)\n }\n\n async deleteVisitor(visitorId: string): Promise<void> {\n await this.col('visitors').deleteOne({ visitor_id: visitorId })\n }\n\n async getVisitor(visitorId: string): Promise<Visitor | null> {\n const doc = cast<DocVisitor>(await this.col('visitors').findOne({ visitor_id: visitorId }))\n return doc ? mapVisitor(doc) : null\n }\n\n async getVisitors(filters: VisitorFilters): Promise<Visitor[]> {\n const q: Record<string, unknown> = { tenant_id: filters.tenantId }\n if (filters.from != null || filters.to != null) {\n const r: Record<string, string> = {}\n if (filters.from != null) r['$gte'] = filters.from\n if (filters.to != null) r['$lte'] = filters.to\n q['first_seen'] = r\n }\n const page = filters.page ?? 1\n const limit = filters.limit ?? 50\n const docs = castArr<DocVisitor>(\n await this.col('visitors').find(q).sort({ first_seen: -1 }).skip((page - 1) * limit).limit(limit).toArray(),\n )\n return docs.map(mapVisitor)\n }\n\n // ── Stats ─────────────────────────────────────────────────────────────────────\n\n async getOverviewStats(tenantId: string): Promise<OverviewStats> {\n const [total, gpcCount, visitors] = await Promise.all([\n this.col('consent_records').countDocuments({ tenant_id: tenantId }),\n this.col('consent_records').countDocuments({ tenant_id: tenantId, gpc_detected: true }),\n this.col('visitors').countDocuments({ tenant_id: tenantId }),\n ])\n\n const pipeline = [\n { $match: { tenant_id: tenantId } },\n { $addFields: { values: { $objectToArray: '$consent_json' } } },\n { $unwind: '$values' },\n { $group: { _id: '$values.v', count: { $sum: 1 } } },\n ]\n const results = await this.col('consent_records').aggregate(pipeline).toArray() as Array<{ _id: string; count: number }>\n\n let granted = 0, denied = 0, all = 0\n for (const r of results) {\n all += r.count\n if (r._id === 'granted') granted = r.count\n if (r._id === 'denied') denied = r.count\n }\n return {\n totalConsents: total,\n acceptedPct: all > 0 ? Math.round((granted / all) * 100) : 0,\n rejectedPct: all > 0 ? Math.round((denied / all) * 100) : 0,\n totalVisitors: visitors,\n gpcDetectedCount: gpcCount,\n }\n }\n\n async getCategoryStats(tenantId: string): Promise<CategoryStats> {\n const pipeline = [\n { $match: { tenant_id: tenantId } },\n { $addFields: { pairs: { $objectToArray: '$consent_json' } } },\n { $unwind: '$pairs' },\n { $group: { _id: { cookie: '$pairs.k', status: '$pairs.v' }, count: { $sum: 1 } } },\n ]\n const rows = await this.col('consent_records').aggregate(pipeline).toArray() as Array<{ _id: { cookie: string; status: string }; count: number }>\n const result: CategoryStats = {}\n for (const r of rows) {\n const cookie = r._id.cookie\n if (!result[cookie]) result[cookie] = { granted: 0, denied: 0, objected: 0 }\n const entry = result[cookie]\n if (entry) {\n if (r._id.status === 'granted') entry.granted += r.count\n if (r._id.status === 'denied') entry.denied += r.count\n if (r._id.status === 'objected') entry.objected += r.count\n }\n }\n return result\n }\n\n async getTimeline(tenantId: string, days = 30): Promise<TimelineEntry[]> {\n const from = new Date(Date.now() - days * 86400_000).toISOString()\n const pipeline = [\n { $match: { tenant_id: tenantId, created_at: { $gte: from } } },\n { $group: { _id: { $substr: ['$created_at', 0, 10] }, count: { $sum: 1 } } },\n { $sort: { _id: 1 } },\n ]\n const rows = await this.col('consent_records').aggregate(pipeline).toArray() as Array<{ _id: string; count: number }>\n return rows.map(r => ({ date: r._id, count: r.count }))\n }\n\n // ── Users ─────────────────────────────────────────────────────────────────────\n\n async createUser(data: CreateUserInput): Promise<AdminUser> {\n const now = new Date().toISOString()\n const doc: DocUser = {\n _id: randomUUID(), tenant_id: data.tenantId, name: data.name,\n email: data.email, password_hash: data.passwordHash,\n is_active: true, created_at: now, updated_at: now,\n }\n await this.col('users').insertOne(doc)\n return mapUser(doc)\n }\n\n async updateUser(id: string, data: UpdateUserInput): Promise<AdminUser> {\n const set: Record<string, unknown> = { updated_at: new Date().toISOString() }\n if (data.name != null) set['name'] = data.name\n if (data.email != null) set['email'] = data.email\n if (data.passwordHash != null) set['password_hash'] = data.passwordHash\n if (data.isActive != null) set['is_active'] = data.isActive\n const res = cast<DocUser>(await this.col('users').findOneAndUpdate(\n { _id: id }, { $set: set }, { returnDocument: 'after' },\n ))\n if (!res) throw new Error(`User ${id} not found`)\n return mapUser(res)\n }\n\n async deleteUser(id: string): Promise<void> {\n await this.col('user_roles').deleteMany({ user_id: id })\n await this.col('users').deleteOne({ _id: id })\n }\n\n async getUserById(id: string): Promise<AdminUser | null> {\n const doc = cast<DocUser>(await this.col('users').findOne({ _id: id }))\n return doc ? mapUser(doc) : null\n }\n\n async getUserByEmail(email: string): Promise<AdminUser | null> {\n const doc = cast<DocUser>(await this.col('users').findOne({ email }))\n return doc ? mapUser(doc) : null\n }\n\n async getUsers(tenantId: string): Promise<AdminUser[]> {\n const docs = castArr<DocUser>(await this.col('users').find({ tenant_id: tenantId }).toArray())\n return docs.map(mapUser)\n }\n\n async countUsers(tenantId?: string): Promise<number> {\n return this.col('users').countDocuments(tenantId ? { tenant_id: tenantId } : {})\n }\n\n // ── Roles & permissions ───────────────────────────────────────────────────────\n\n async getRoles(tenantId: string): Promise<Role[]> {\n const docs = castArr<DocRole>(await this.col('roles').find({ tenant_id: tenantId }).toArray())\n return docs.map(mapRole)\n }\n\n async createRole(data: CreateRoleInput): Promise<Role> {\n const doc: DocRole = {\n _id: randomUUID(), tenant_id: data.tenantId, name: data.name,\n ...(data.description != null ? { description: data.description } : {}),\n }\n await this.col('roles').insertOne(doc)\n return mapRole(doc)\n }\n\n async updateRole(id: string, data: UpdateRoleInput): Promise<Role> {\n const set: Record<string, string> = {}\n if (data.name != null) set['name'] = data.name\n if (data.description != null) set['description'] = data.description\n const res = cast<DocRole>(await this.col('roles').findOneAndUpdate(\n { _id: id }, { $set: set }, { returnDocument: 'after' },\n ))\n if (!res) throw new Error(`Role ${id} not found`)\n return mapRole(res)\n }\n\n async deleteRole(id: string): Promise<void> {\n await this.col('role_permissions').deleteMany({ role_id: id })\n await this.col('user_roles').deleteMany({ role_id: id })\n await this.col('roles').deleteOne({ _id: id })\n }\n\n async getAllPermissions(): Promise<Permission[]> {\n const docs = castArr<DocPermission>(await this.col('permissions').find({}).toArray())\n return docs.map(mapPermission)\n }\n\n async getPermissionsForRole(roleId: string): Promise<Permission[]> {\n const rps = castArr<DocRolePermission>(\n await this.col('role_permissions').find({ role_id: roleId }).toArray(),\n )\n const ids = rps.map(r => r.permission_id)\n if (ids.length === 0) return []\n const docs = castArr<DocPermission>(await this.col('permissions').find({ _id: { $in: ids } }).toArray())\n return docs.map(mapPermission)\n }\n\n async getUserRoles(userId: string, tenantId?: string): Promise<Role[]> {\n const filter = tenantId\n ? { user_id: userId, tenant_id: tenantId }\n : { user_id: userId }\n const urs = castArr<DocUserRole>(await this.col('user_roles').find(filter).toArray())\n const ids = urs.map(r => r.role_id)\n if (ids.length === 0) return []\n const docs = castArr<DocRole>(await this.col('roles').find({ _id: { $in: ids } }).toArray())\n return docs.map(mapRole)\n }\n\n async assignRole(userId: string, roleId: string, tenantId = 'default'): Promise<void> {\n await this.col('user_roles').updateOne(\n { user_id: userId, role_id: roleId, tenant_id: tenantId },\n { $setOnInsert: { user_id: userId, role_id: roleId, tenant_id: tenantId } },\n { upsert: true },\n )\n }\n\n async revokeRole(userId: string, roleId: string, tenantId?: string): Promise<void> {\n if (tenantId) {\n await this.col('user_roles').deleteOne({ user_id: userId, role_id: roleId, tenant_id: tenantId })\n } else {\n await this.col('user_roles').deleteMany({ user_id: userId, role_id: roleId })\n }\n }\n\n async assignPermissionToRole(roleId: string, permissionId: string): Promise<void> {\n await this.col('role_permissions').updateOne(\n { role_id: roleId, permission_id: permissionId },\n { $setOnInsert: { role_id: roleId, permission_id: permissionId } },\n { upsert: true },\n )\n }\n\n async revokePermissionFromRole(roleId: string, permissionId: string): Promise<void> {\n await this.col('role_permissions').deleteOne({ role_id: roleId, permission_id: permissionId })\n }\n\n // ── Audit logs ────────────────────────────────────────────────────────────────\n\n async createLog(data: CreateAuditLogInput): Promise<void> {\n const doc: DocAuditLog = {\n _id: randomUUID(), tenant_id: data.tenantId, action: data.action,\n resource_type: data.resourceType,\n ...(data.userId != null ? { user_id: data.userId } : {}),\n ...(data.resourceId != null ? { resource_id: data.resourceId } : {}),\n ...(data.oldData != null ? { old_data: data.oldData } : {}),\n ...(data.newData != null ? { new_data: data.newData } : {}),\n created_at: new Date().toISOString(),\n }\n await this.col('audit_logs').insertOne(doc)\n }\n\n async getLogs(filters: AuditFilters): Promise<AuditLog[]> {\n const q = this.buildAuditFilter(filters)\n const page = filters.page ?? 1\n const limit = filters.limit ?? 50\n const docs = castArr<DocAuditLog>(\n await this.col('audit_logs').find(q).sort({ created_at: -1 }).skip((page - 1) * limit).limit(limit).toArray(),\n )\n return docs.map(mapAuditLog)\n }\n\n async *streamAuditLogs(filters: AuditFilters): AsyncIterable<AuditLog> {\n const q = this.buildAuditFilter(filters)\n const cursor = this.col('audit_logs').find(q).sort({ created_at: 1 })\n for await (const doc of cursor) yield mapAuditLog(doc as unknown as DocAuditLog)\n }\n\n private buildAuditFilter(f: AuditFilters): Record<string, unknown> {\n const q: Record<string, unknown> = { tenant_id: f.tenantId }\n if (f.action != null) q['action'] = f.action\n if (f.resourceType != null) q['resource_type'] = f.resourceType\n if (f.from != null || f.to != null) {\n const r: Record<string, string> = {}\n if (f.from != null) r['$gte'] = f.from\n if (f.to != null) r['$lte'] = f.to\n q['created_at'] = r\n }\n return q\n }\n\n // ── Stats extensions ──────────────────────────────────────────────────────────\n\n async getCountries(tenantId: string): Promise<CountryStat[]> {\n const pipeline = [\n { $match: { tenant_id: tenantId } },\n { $lookup: { from: 'visitors', localField: 'visitor_id', foreignField: 'visitor_id', as: 'v' } },\n { $unwind: '$v' },\n { $match: { 'v.country': { $ne: null } } },\n { $group: { _id: '$v.country', count: { $sum: 1 } } },\n { $sort: { count: -1 } },\n { $limit: 50 },\n ]\n const rows = await this.col('consent_records').aggregate(pipeline).toArray() as Array<{ _id: string; count: number }>\n return rows.map(r => ({ country: r._id, count: r.count }))\n }\n\n async getGpcStats(tenantId: string): Promise<GpcStats> {\n const total = await this.col('consent_records').countDocuments({ tenant_id: tenantId })\n const detected = await this.col('consent_records').countDocuments({ tenant_id: tenantId, gpc_detected: true })\n return { detected, total, rate: total > 0 ? Math.round((detected / total) * 100) : 0 }\n }\n\n // ── Tenants ───────────────────────────────────────────────────────────────────\n\n async getTenants(): Promise<Tenant[]> {\n const docs = castArr<{ _id: string; name: string; slug: string; created_at: string; updated_at: string }>(\n await this.col('tenants').find({}).toArray()\n )\n return docs.map(d => ({ id: d._id, name: d.name, slug: d.slug, createdAt: d.created_at, updatedAt: d.updated_at }))\n }\n\n // ── API Keys ──────────────────────────────────────────────────────────────────\n\n async createApiKey(data: CreateApiKeyInput): Promise<ApiKey> {\n const doc: DocApiKey = {\n _id: randomUUID(), tenant_id: data.tenantId, key_hash: data.keyHash,\n name: data.name, is_active: true, created_at: new Date().toISOString(),\n }\n await this.col('api_keys').insertOne(doc)\n return { id: doc._id, tenantId: doc.tenant_id, keyHash: doc.key_hash, name: doc.name, isActive: doc.is_active, createdAt: doc.created_at }\n }\n\n async getApiKeyByHash(keyHash: string): Promise<ApiKey | null> {\n const doc = cast<DocApiKey>(await this.col('api_keys').findOne({ key_hash: keyHash, is_active: true }))\n if (!doc) return null\n return { id: doc._id, tenantId: doc.tenant_id, keyHash: doc.key_hash, name: doc.name, isActive: doc.is_active, createdAt: doc.created_at }\n }\n\n async revokeApiKey(id: string): Promise<void> {\n await this.col('api_keys').updateOne({ _id: id }, { $set: { is_active: false } })\n }\n\n async getApiKeys(tenantId: string): Promise<ApiKey[]> {\n const docs = castArr<DocApiKey>(await this.col('api_keys').find({ tenant_id: tenantId }).sort({ created_at: -1 }).toArray())\n return docs.map(d => ({ id: d._id, tenantId: d.tenant_id, keyHash: d.key_hash, name: d.name, isActive: d.is_active, createdAt: d.created_at }))\n }\n\n async createTenant(data: CreateTenantInput): Promise<Tenant> {\n const id = randomUUID()\n const now = new Date().toISOString()\n const doc = { _id: id, name: data.name, slug: data.slug, created_at: now, updated_at: now }\n await this.col('tenants').insertOne(doc)\n return { id, name: data.name, slug: data.slug, createdAt: now, updatedAt: now }\n }\n\n async updateTenant(id: string, data: UpdateTenantInput): Promise<Tenant> {\n const now = new Date().toISOString()\n const update: Record<string, string> = { updated_at: now }\n if (data.name != null) update['name'] = data.name\n if (data.slug != null) update['slug'] = data.slug\n await this.col('tenants').updateOne({ _id: id }, { $set: update })\n const doc = cast<{ _id: string; name: string; slug: string; created_at: string; updated_at: string }>(\n await this.col('tenants').findOne({ _id: id })\n )\n if (!doc) throw new Error(`Tenant ${id} not found`)\n return { id: doc._id, name: doc.name, slug: doc.slug, createdAt: doc.created_at, updatedAt: doc.updated_at }\n }\n\n async deleteTenant(id: string): Promise<void> {\n await this.col('tenants').deleteOne({ _id: id })\n }\n\n async purgeExpiredConsents(olderThanDays: number): Promise<number> {\n const cutoff = new Date(Date.now() - olderThanDays * 86_400_000).toISOString()\n const docs = castArr<{ visitor_id: string }>(\n await this.col('consent_records').find({ created_at: { $lt: cutoff } }).toArray()\n )\n if (docs.length === 0) return 0\n const visitorIds = docs.map(d => d.visitor_id)\n await this.col('consent_history').deleteMany({ visitor_id: { $in: visitorIds } })\n await this.col('consent_records').deleteMany({ visitor_id: { $in: visitorIds } })\n return docs.length\n }\n\n // Template methods — not yet implemented for MongoDB adapter\n async createCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async updateCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async deleteCookieTemplate(): Promise<void> { throw new Error('Not implemented') }\n async getCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async getCookieTemplates(): Promise<never> { throw new Error('Not implemented') }\n async copyCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async createUITemplate(): Promise<never> { throw new Error('Not implemented') }\n async updateUITemplate(): Promise<never> { throw new Error('Not implemented') }\n async deleteUITemplate(): Promise<void> { throw new Error('Not implemented') }\n async getUITemplate(): Promise<never> { throw new Error('Not implemented') }\n async getUITemplates(): Promise<never> { throw new Error('Not implemented') }\n async copyUITemplate(): Promise<never> { throw new Error('Not implemented') }\n\n // Profile summary / analytics — not yet implemented for MongoDB adapter\n async listProfilesSummary(): Promise<never[]> { return [] }\n async findProfilesUsingCookieTemplate(): Promise<never[]> { return [] }\n async findProfilesUsingUITemplate(): Promise<never[]> { return [] }\n async getOptInStats(): Promise<never> { throw new Error('Not implemented') }\n}\n","import type { Pool, PoolConnection, RowDataPacket, ResultSetHeader } from 'mysql2/promise'\nimport { randomUUID } from '../../utils/crypto'\nimport { SEED_TENANT, SEED_PERMISSIONS, SEED_ROLES, SEED_ROLE_PERMISSIONS, SCHEMA_SQL_MYSQL } from '../seed-data'\nimport type {\n StorageAdapter, StorageConfig, Profile, ProfileConfig,\n CreateProfileInput, UpdateProfileInput,\n ConsentDbRecord, ConsentHistoryEntry, ConsentValue, ConsentFilters,\n CreateConsentInput, UpdateConsentInput,\n Visitor, VisitorFilters, CreateVisitorInput, UpdateVisitorInput,\n AdminUser, CreateUserInput, UpdateUserInput,\n Role, CreateRoleInput, UpdateRoleInput,\n Permission, AuditLog, AuditFilters, CreateAuditLogInput,\n OverviewStats, CategoryStats, TimelineEntry,\n CountryStat, GpcStats, Tenant, ApiKey, CreateApiKeyInput,\n CreateTenantInput, UpdateTenantInput,\n} from '@consenti/types'\n\n// ── Raw row shapes ─────────────────────────────────────────────────────────────\n\ninterface RowProfile extends RowDataPacket {\n id: string; tenant_id: string; name: string; default_locale: string\n version: number; profile_json: string\n created_at: string; updated_at: string\n}\ninterface RowConsent extends RowDataPacket {\n id: string; tenant_id: string; visitor_id: string; profile_id: string\n profile_version: number; locale: string; consent_json: string\n gpc_detected: number; source: string; created_at: string; updated_at: string\n age_verified?: number; parental_consent_token?: string | null; tcf_string?: string | null\n}\ninterface RowConsentHistory extends RowDataPacket {\n id: string; tenant_id: string; consent_record_id: string; visitor_id: string\n old_json: string | null; new_json: string; action: string; created_at: string\n}\ninterface RowVisitor extends RowDataPacket {\n id: string; tenant_id: string; visitor_id: string\n country: string | null; region: string | null; city: string | null\n ip_hash: string | null; user_agent_hash: string | null\n first_seen: string; last_seen: string\n}\ninterface RowUser extends RowDataPacket {\n id: string; tenant_id: string; name: string; email: string\n password_hash: string; is_active: number; created_at: string; updated_at: string\n totp_secret?: string | null; totp_enabled?: number\n}\ninterface RowRole extends RowDataPacket {\n id: string; tenant_id: string; name: string; description: string | null\n}\ninterface RowPermission extends RowDataPacket {\n id: string; name: string; description: string | null\n}\ninterface RowAuditLog extends RowDataPacket {\n id: string; tenant_id: string; user_id: string | null; action: string\n resource_type: string; resource_id: string | null\n old_data: string | null; new_data: string | null; created_at: string\n}\ninterface RowCount extends RowDataPacket { total: number }\ninterface RowStatus extends RowDataPacket { status: string; count: number }\ninterface RowDateCount extends RowDataPacket { date: string; count: number }\ninterface RowCookieStatus extends RowDataPacket { cookie_id: string; status: string; count: number }\ninterface RowCountry extends RowDataPacket { country: string; count: number }\ninterface RowApiKey extends RowDataPacket {\n id: string; tenant_id: string; key_hash: string; name: string; is_active: number; created_at: string\n}\ninterface RowTenant extends RowDataPacket { id: string; name: string; slug: string; created_at: string; updated_at: string }\n\n// ── Mappers ────────────────────────────────────────────────────────────────────\n\nfunction mapProfile(r: RowProfile): Profile {\n return {\n id: r.id, tenantId: r.tenant_id, name: r.name,\n defaultLocale: r.default_locale, version: r.version,\n profileJson: JSON.parse(r.profile_json) as ProfileConfig,\n createdAt: r.created_at, updatedAt: r.updated_at,\n }\n}\n\nfunction mapConsent(r: RowConsent): ConsentDbRecord {\n return {\n id: r.id, tenantId: r.tenant_id, visitorId: r.visitor_id, profileId: r.profile_id,\n profileVersion: r.profile_version, locale: r.locale,\n consentJson: JSON.parse(r.consent_json) as ConsentValue,\n gpcDetected: r.gpc_detected === 1, source: r.source as ConsentDbRecord['source'],\n createdAt: r.created_at, updatedAt: r.updated_at,\n ...(r.age_verified != null ? { ageVerified: r.age_verified === 1 } : {}),\n ...(r.parental_consent_token != null ? { parentalConsentToken: r.parental_consent_token } : {}),\n ...(r.tcf_string != null ? { tcfString: r.tcf_string } : {}),\n }\n}\n\nfunction mapHistory(r: RowConsentHistory): ConsentHistoryEntry {\n return {\n id: r.id, tenantId: r.tenant_id, consentRecordId: r.consent_record_id,\n visitorId: r.visitor_id,\n oldJson: r.old_json ? JSON.parse(r.old_json) as ConsentValue : null,\n newJson: JSON.parse(r.new_json) as ConsentValue,\n action: r.action as ConsentHistoryEntry['action'], createdAt: r.created_at,\n }\n}\n\nfunction mapVisitor(r: RowVisitor): Visitor {\n return {\n id: r.id, tenantId: r.tenant_id, visitorId: r.visitor_id,\n ...(r.country != null ? { country: r.country } : {}),\n ...(r.region != null ? { region: r.region } : {}),\n ...(r.city != null ? { city: r.city } : {}),\n ...(r.ip_hash != null ? { ipHash: r.ip_hash } : {}),\n ...(r.user_agent_hash != null ? { userAgentHash: r.user_agent_hash } : {}),\n firstSeen: r.first_seen, lastSeen: r.last_seen,\n }\n}\n\nfunction mapUser(r: RowUser): AdminUser {\n return {\n id: r.id, tenantId: r.tenant_id, name: r.name, email: r.email,\n passwordHash: r.password_hash, isActive: r.is_active === 1,\n createdAt: r.created_at, updatedAt: r.updated_at,\n totpEnabled: r.totp_enabled === 1,\n ...(r.totp_secret != null ? { totpSecret: r.totp_secret } : {}),\n }\n}\n\nfunction mapRole(r: RowRole): Role {\n return {\n id: r.id, tenantId: r.tenant_id, name: r.name,\n ...(r.description != null ? { description: r.description } : {}),\n }\n}\n\nfunction mapPermission(r: RowPermission): Permission {\n return {\n id: r.id, name: r.name,\n ...(r.description != null ? { description: r.description } : {}),\n }\n}\n\nfunction mapAuditLog(r: RowAuditLog): AuditLog {\n return {\n id: r.id, tenantId: r.tenant_id, action: r.action, resourceType: r.resource_type,\n ...(r.user_id != null ? { userId: r.user_id } : {}),\n ...(r.resource_id != null ? { resourceId: r.resource_id } : {}),\n ...(r.old_data != null ? { oldData: JSON.parse(r.old_data) as unknown } : {}),\n ...(r.new_data != null ? { newData: JSON.parse(r.new_data) as unknown } : {}),\n createdAt: r.created_at,\n }\n}\n\n// ── Adapter ────────────────────────────────────────────────────────────────────\n\nexport class MySQLAdapter implements StorageAdapter {\n private pool!: Pool\n\n constructor(private config: StorageConfig) { }\n\n private async q<T extends RowDataPacket>(sql: string, params: (string | number | boolean | null)[] = []): Promise<T[]> {\n const [rows] = await this.pool.query<T[]>(sql, params)\n return rows\n }\n\n private async exec(sql: string, params: (string | number | boolean | null)[] = []): Promise<ResultSetHeader> {\n const [result] = await this.pool.query<ResultSetHeader>(sql, params)\n return result\n }\n\n async connect(): Promise<void> {\n const mysql = (await import('mysql2/promise')) as { createPool: typeof import('mysql2/promise').createPool }\n const cfg = this.config\n if (cfg.uri) {\n this.pool = mysql.createPool(cfg.uri)\n } else {\n this.pool = mysql.createPool({\n host: cfg.host ?? 'localhost',\n port: cfg.port ?? 3306,\n user: cfg.user ?? 'root',\n password: cfg.password ?? '',\n database: cfg.database ?? 'consenti',\n })\n }\n await this.migrate()\n }\n\n async disconnect(): Promise<void> {\n await this.pool.end()\n }\n\n async migrate(): Promise<void> {\n const conn: PoolConnection = await this.pool.getConnection()\n try {\n const [tables] = await conn.query<RowDataPacket[]>('SHOW TABLES LIKE ?', ['schema_version'])\n if (tables.length === 0) {\n for (const stmt of SCHEMA_SQL_MYSQL.split(';').map(s => s.trim()).filter(Boolean)) {\n await conn.query(stmt)\n }\n await this.seed(conn)\n await conn.query('INSERT IGNORE INTO schema_version (version) VALUES (2)')\n return\n }\n const [vrows] = await conn.query<RowDataPacket[]>('SELECT version FROM schema_version ORDER BY version DESC LIMIT 1')\n const version = (vrows[0] as { version?: number } | undefined)?.version ?? 0\n if (version < 2) {\n const alters = [\n 'ALTER TABLE consent_records ADD COLUMN IF NOT EXISTS age_verified TINYINT(1) NOT NULL DEFAULT 0',\n 'ALTER TABLE consent_records ADD COLUMN IF NOT EXISTS parental_consent_token TEXT',\n 'ALTER TABLE consent_records ADD COLUMN IF NOT EXISTS tcf_string TEXT',\n 'ALTER TABLE users ADD COLUMN IF NOT EXISTS totp_secret TEXT',\n 'ALTER TABLE users ADD COLUMN IF NOT EXISTS totp_enabled TINYINT(1) NOT NULL DEFAULT 0',\n ]\n for (const stmt of alters) await conn.query(stmt)\n await conn.query('INSERT IGNORE INTO schema_version (version) VALUES (2)')\n }\n if (version < 3) {\n await conn.query('ALTER TABLE user_roles ADD COLUMN IF NOT EXISTS tenant_id VARCHAR(36) NOT NULL DEFAULT \\'default\\'')\n await conn.query('INSERT IGNORE INTO schema_version (version) VALUES (3)')\n }\n } finally {\n conn.release()\n }\n }\n\n private async seed(conn: PoolConnection): Promise<void> {\n await conn.query('INSERT IGNORE INTO tenants (id, name, slug) VALUES (?,?,?)', [SEED_TENANT.id, SEED_TENANT.name, SEED_TENANT.slug])\n for (const p of SEED_PERMISSIONS) {\n await conn.query('INSERT IGNORE INTO permissions (id, name, description) VALUES (?,?,?)', [p.id, p.name, p.description])\n }\n for (const r of SEED_ROLES) {\n await conn.query('INSERT IGNORE INTO roles (id, tenant_id, name, description) VALUES (?,?,?,?)', [r.id, r.tenantId, r.name, r.description])\n }\n for (const { roleId, permissionId } of SEED_ROLE_PERMISSIONS) {\n await conn.query('INSERT IGNORE INTO role_permissions (role_id, permission_id) VALUES (?,?)', [roleId, permissionId])\n }\n }\n\n // ── Profiles ─────────────────────────────────────────────────────────────────\n\n async createProfile(data: CreateProfileInput): Promise<Profile> {\n const id = randomUUID()\n await this.exec(\n 'INSERT INTO profiles (id, tenant_id, name, default_locale, profile_json) VALUES (?,?,?,?,?)',\n [id, data.tenantId, data.name, data.defaultLocale, JSON.stringify(data.profileJson)],\n )\n const rows = await this.q<RowProfile>('SELECT * FROM profiles WHERE id=?', [id])\n const row = rows[0]\n if (!row) throw new Error('Profile creation failed')\n return mapProfile(row)\n }\n\n async updateProfile(id: string, data: UpdateProfileInput): Promise<Profile> {\n const sets: string[] = ['version = version + 1']\n const vals: (string | number | boolean | null)[] = []\n if (data.name != null) { sets.push('name=?'); vals.push(data.name) }\n if (data.defaultLocale != null) { sets.push('default_locale=?'); vals.push(data.defaultLocale) }\n if (data.profileJson != null) { sets.push('profile_json=?'); vals.push(JSON.stringify(data.profileJson)) }\n vals.push(id)\n await this.exec(`UPDATE profiles SET ${sets.join(',')} WHERE id=?`, vals)\n const rows = await this.q<RowProfile>('SELECT * FROM profiles WHERE id=?', [id])\n const row = rows[0]\n if (!row) throw new Error(`Profile ${id} not found`)\n return mapProfile(row)\n }\n\n async deleteProfile(id: string): Promise<void> {\n await this.exec('DELETE FROM profiles WHERE id=?', [id])\n }\n\n async getProfile(id: string): Promise<Profile | null> {\n const rows = await this.q<RowProfile>('SELECT * FROM profiles WHERE id=?', [id])\n return rows[0] ? mapProfile(rows[0]) : null\n }\n\n async getProfiles(tenantId: string): Promise<Profile[]> {\n const rows = await this.q<RowProfile>('SELECT * FROM profiles WHERE tenant_id=? ORDER BY created_at DESC', [tenantId])\n return rows.map(mapProfile)\n }\n\n async findActiveProfileByComplianceGroup(tenantId: string, complianceGroup: string): Promise<Profile | null> {\n const profiles = await this.getProfiles(tenantId)\n return profiles.find(p => p.profileJson.complianceGroup === complianceGroup && p.profileJson.isActive) ?? null\n }\n\n // ── Consents ─────────────────────────────────────────────────────────────────\n\n async createConsent(data: CreateConsentInput): Promise<ConsentDbRecord> {\n const id = randomUUID()\n await this.exec(\n 'INSERT INTO consent_records (id, tenant_id, visitor_id, profile_id, profile_version, locale, consent_json, gpc_detected, source) VALUES (?,?,?,?,?,?,?,?,?)',\n [id, data.tenantId, data.visitorId, data.profileId, data.profileVersion, data.locale,\n JSON.stringify(data.consentJson), data.gpcDetected ? 1 : 0, data.source],\n )\n const rows = await this.q<RowConsent>('SELECT * FROM consent_records WHERE id=?', [id])\n const row = rows[0]\n if (!row) throw new Error('Consent creation failed')\n await this.writeHistory(id, data.tenantId, data.visitorId, null, data.consentJson, 'created')\n return mapConsent(row)\n }\n\n async updateConsent(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord> {\n const existing = await this.getConsent(visitorId)\n if (!existing) throw new Error(`Consent for visitor ${visitorId} not found`)\n const sets: string[] = ['consent_json=?']\n const vals: (string | number | boolean | null)[] = [JSON.stringify(data.consentJson)]\n if (data.locale != null) { sets.push('locale=?'); vals.push(data.locale) }\n if (data.gpcDetected != null) { sets.push('gpc_detected=?'); vals.push(data.gpcDetected ? 1 : 0) }\n vals.push(visitorId)\n await this.exec(`UPDATE consent_records SET ${sets.join(',')} WHERE visitor_id=?`, vals)\n const rows = await this.q<RowConsent>('SELECT * FROM consent_records WHERE visitor_id=?', [visitorId])\n const row = rows[0]\n if (!row) throw new Error(`Consent for visitor ${visitorId} not found`)\n await this.writeHistory(row.id, row.tenant_id, visitorId, existing.consentJson, data.consentJson, 'updated')\n return mapConsent(row)\n }\n\n async deleteConsent(visitorId: string): Promise<void> {\n await this.exec('DELETE FROM consent_history WHERE visitor_id=?', [visitorId])\n await this.exec('DELETE FROM consent_records WHERE visitor_id=?', [visitorId])\n }\n\n async getConsent(visitorId: string): Promise<ConsentDbRecord | null> {\n const rows = await this.q<RowConsent>('SELECT * FROM consent_records WHERE visitor_id=?', [visitorId])\n return rows[0] ? mapConsent(rows[0]) : null\n }\n\n async getConsents(filters: ConsentFilters): Promise<ConsentDbRecord[]> {\n const { sql, params } = this.buildConsentQuery(filters)\n const page = filters.page ?? 1\n const limit = filters.limit ?? 50\n const rows = await this.q<RowConsent>(`${sql} ORDER BY created_at DESC LIMIT ? OFFSET ?`, [...params, limit, (page - 1) * limit])\n return rows.map(mapConsent)\n }\n\n async *streamConsents(filters: ConsentFilters): AsyncIterable<ConsentDbRecord> {\n const { sql, params } = this.buildConsentQuery(filters)\n const rows = await this.q<RowConsent>(`${sql} ORDER BY created_at ASC`, params)\n for (const r of rows) yield mapConsent(r)\n }\n\n private buildConsentQuery(f: ConsentFilters): { sql: string; params: (string | number | boolean | null)[] } {\n let sql = 'SELECT * FROM consent_records WHERE tenant_id=?'\n const params: (string | number | boolean | null)[] = [f.tenantId]\n if (f.profileId != null) { sql += ' AND profile_id=?'; params.push(f.profileId) }\n if (f.from != null) { sql += ' AND created_at>=?'; params.push(f.from) }\n if (f.to != null) { sql += ' AND created_at<=?'; params.push(f.to) }\n return { sql, params }\n }\n\n private async writeHistory(\n consentRecordId: string, tenantId: string, visitorId: string,\n oldJson: ConsentValue | null, newJson: ConsentValue, action: string,\n ): Promise<void> {\n await this.exec(\n 'INSERT INTO consent_history (id, tenant_id, consent_record_id, visitor_id, old_json, new_json, action) VALUES (?,?,?,?,?,?,?)',\n [randomUUID(), tenantId, consentRecordId, visitorId,\n oldJson ? JSON.stringify(oldJson) : null, JSON.stringify(newJson), action],\n )\n }\n\n async getConsentHistory(visitorId: string): Promise<ConsentHistoryEntry[]> {\n const rows = await this.q<RowConsentHistory>('SELECT * FROM consent_history WHERE visitor_id=? ORDER BY created_at ASC', [visitorId])\n return rows.map(mapHistory)\n }\n\n // ── Visitors ─────────────────────────────────────────────────────────────────\n\n async createVisitor(data: CreateVisitorInput): Promise<Visitor> {\n const id = randomUUID()\n await this.exec(\n 'INSERT INTO visitors (id, tenant_id, visitor_id, country, region, city, ip_hash, user_agent_hash) VALUES (?,?,?,?,?,?,?,?)',\n [id, data.tenantId, data.visitorId,\n data.country ?? null, data.region ?? null, data.city ?? null,\n data.ipHash ?? null, data.userAgentHash ?? null],\n )\n const rows = await this.q<RowVisitor>('SELECT * FROM visitors WHERE id=?', [id])\n const row = rows[0]\n if (!row) throw new Error('Visitor creation failed')\n return mapVisitor(row)\n }\n\n async updateVisitor(visitorId: string, data: UpdateVisitorInput): Promise<Visitor> {\n const sets: string[] = ['last_seen=NOW()']\n const vals: (string | number | boolean | null)[] = []\n if (data.country != null) { sets.push('country=?'); vals.push(data.country) }\n if (data.region != null) { sets.push('region=?'); vals.push(data.region) }\n if (data.city != null) { sets.push('city=?'); vals.push(data.city) }\n vals.push(visitorId)\n await this.exec(`UPDATE visitors SET ${sets.join(',')} WHERE visitor_id=?`, vals)\n const rows = await this.q<RowVisitor>('SELECT * FROM visitors WHERE visitor_id=?', [visitorId])\n const row = rows[0]\n if (!row) throw new Error(`Visitor ${visitorId} not found`)\n return mapVisitor(row)\n }\n\n async deleteVisitor(visitorId: string): Promise<void> {\n await this.exec('DELETE FROM visitors WHERE visitor_id=?', [visitorId])\n }\n\n async getVisitor(visitorId: string): Promise<Visitor | null> {\n const rows = await this.q<RowVisitor>('SELECT * FROM visitors WHERE visitor_id=?', [visitorId])\n return rows[0] ? mapVisitor(rows[0]) : null\n }\n\n async getVisitors(filters: VisitorFilters): Promise<Visitor[]> {\n let sql = 'SELECT * FROM visitors WHERE tenant_id=?'\n const params: (string | number | boolean | null)[] = [filters.tenantId]\n if (filters.from != null) { sql += ' AND first_seen>=?'; params.push(filters.from) }\n if (filters.to != null) { sql += ' AND first_seen<=?'; params.push(filters.to) }\n const page = filters.page ?? 1\n const limit = filters.limit ?? 50\n const rows = await this.q<RowVisitor>(`${sql} ORDER BY first_seen DESC LIMIT ? OFFSET ?`, [...params, limit, (page - 1) * limit])\n return rows.map(mapVisitor)\n }\n\n // ── Stats ─────────────────────────────────────────────────────────────────────\n\n async getOverviewStats(tenantId: string): Promise<OverviewStats> {\n const [[countRow], [gpcRow], [visitorRow]] = await Promise.all([\n this.q<RowCount>('SELECT COUNT(*) AS total FROM consent_records WHERE tenant_id=?', [tenantId]),\n this.q<RowCount>('SELECT COUNT(*) AS total FROM consent_records WHERE tenant_id=? AND gpc_detected=1', [tenantId]),\n this.q<RowCount>('SELECT COUNT(*) AS total FROM visitors WHERE tenant_id=?', [tenantId]),\n ])\n const total = countRow?.total ?? 0\n const gpcCount = gpcRow?.total ?? 0\n const visitors = visitorRow?.total ?? 0\n\n const statusRows = await this.q<RowStatus>(\n `SELECT jt.status, COUNT(*) AS count\n FROM consent_records cr\n JOIN JSON_TABLE(cr.consent_json, '$.*' COLUMNS (status VARCHAR(20) PATH '$')) AS jt\n WHERE cr.tenant_id=?\n GROUP BY jt.status`,\n [tenantId],\n )\n let granted = 0, denied = 0, all = 0\n for (const r of statusRows) {\n all += r.count\n if (r.status === 'granted') granted = r.count\n if (r.status === 'denied') denied = r.count\n }\n return {\n totalConsents: total,\n acceptedPct: all > 0 ? Math.round((granted / all) * 100) : 0,\n rejectedPct: all > 0 ? Math.round((denied / all) * 100) : 0,\n totalVisitors: visitors,\n gpcDetectedCount: gpcCount,\n }\n }\n\n async getCategoryStats(tenantId: string): Promise<CategoryStats> {\n const rows = await this.q<RowCookieStatus>(\n `SELECT jt.cookie_id, jt.status, COUNT(*) AS count\n FROM consent_records cr\n JOIN JSON_TABLE(cr.consent_json, '$.*' COLUMNS (NESTED PATH '$' COLUMNS (\n cookie_id VARCHAR(100) PATH '$.k',\n status VARCHAR(20) PATH '$.v'\n ))) AS jt\n WHERE cr.tenant_id=?\n GROUP BY jt.cookie_id, jt.status`,\n [tenantId],\n )\n const result: CategoryStats = {}\n for (const r of rows) {\n if (!result[r.cookie_id]) result[r.cookie_id] = { granted: 0, denied: 0, objected: 0 }\n const entry = result[r.cookie_id]\n if (entry) {\n if (r.status === 'granted') entry.granted += r.count\n if (r.status === 'denied') entry.denied += r.count\n if (r.status === 'objected') entry.objected += r.count\n }\n }\n return result\n }\n\n async getTimeline(tenantId: string, days = 30): Promise<TimelineEntry[]> {\n const from = new Date(Date.now() - days * 86400_000).toISOString().slice(0, 10)\n const rows = await this.q<RowDateCount>(\n `SELECT DATE(created_at) AS date, COUNT(*) AS count\n FROM consent_records WHERE tenant_id=? AND created_at>=?\n GROUP BY DATE(created_at) ORDER BY date ASC`,\n [tenantId, from],\n )\n return rows.map(r => ({ date: String(r.date), count: r.count }))\n }\n\n // ── Users ─────────────────────────────────────────────────────────────────────\n\n async createUser(data: CreateUserInput): Promise<AdminUser> {\n const id = randomUUID()\n await this.exec(\n 'INSERT INTO users (id, tenant_id, name, email, password_hash) VALUES (?,?,?,?,?)',\n [id, data.tenantId, data.name, data.email, data.passwordHash],\n )\n const rows = await this.q<RowUser>('SELECT * FROM users WHERE id=?', [id])\n const row = rows[0]\n if (!row) throw new Error('User creation failed')\n return mapUser(row)\n }\n\n async updateUser(id: string, data: UpdateUserInput): Promise<AdminUser> {\n const sets: string[] = []\n const vals: (string | number | boolean | null)[] = []\n if (data.name != null) { sets.push('name=?'); vals.push(data.name) }\n if (data.email != null) { sets.push('email=?'); vals.push(data.email) }\n if (data.passwordHash != null) { sets.push('password_hash=?'); vals.push(data.passwordHash) }\n if (data.isActive != null) { sets.push('is_active=?'); vals.push(data.isActive ? 1 : 0) }\n if (sets.length > 0) { vals.push(id); await this.exec(`UPDATE users SET ${sets.join(',')} WHERE id=?`, vals) }\n const rows = await this.q<RowUser>('SELECT * FROM users WHERE id=?', [id])\n const row = rows[0]\n if (!row) throw new Error(`User ${id} not found`)\n return mapUser(row)\n }\n\n async deleteUser(id: string): Promise<void> {\n await this.exec('DELETE FROM user_roles WHERE user_id=?', [id])\n await this.exec('DELETE FROM users WHERE id=?', [id])\n }\n\n async getUserById(id: string): Promise<AdminUser | null> {\n const rows = await this.q<RowUser>('SELECT * FROM users WHERE id=?', [id])\n return rows[0] ? mapUser(rows[0]) : null\n }\n\n async getUserByEmail(email: string): Promise<AdminUser | null> {\n const rows = await this.q<RowUser>('SELECT * FROM users WHERE email=?', [email])\n return rows[0] ? mapUser(rows[0]) : null\n }\n\n async getUsers(tenantId: string): Promise<AdminUser[]> {\n const rows = await this.q<RowUser>('SELECT * FROM users WHERE tenant_id=? ORDER BY created_at DESC', [tenantId])\n return rows.map(mapUser)\n }\n\n async countUsers(tenantId?: string): Promise<number> {\n const rows = tenantId\n ? await this.q<RowCount>('SELECT COUNT(*) AS total FROM users WHERE tenant_id=?', [tenantId])\n : await this.q<RowCount>('SELECT COUNT(*) AS total FROM users')\n return rows[0]?.total ?? 0\n }\n\n // ── Roles & permissions ───────────────────────────────────────────────────────\n\n async getRoles(tenantId: string): Promise<Role[]> {\n const rows = await this.q<RowRole>('SELECT * FROM roles WHERE tenant_id=?', [tenantId])\n return rows.map(mapRole)\n }\n\n async createRole(data: CreateRoleInput): Promise<Role> {\n const id = randomUUID()\n await this.exec(\n 'INSERT INTO roles (id, tenant_id, name, description) VALUES (?,?,?,?)',\n [id, data.tenantId, data.name, data.description ?? null],\n )\n const rows = await this.q<RowRole>('SELECT * FROM roles WHERE id=?', [id])\n const row = rows[0]\n if (!row) throw new Error('Role creation failed')\n return mapRole(row)\n }\n\n async updateRole(id: string, data: UpdateRoleInput): Promise<Role> {\n const sets: string[] = []\n const vals: (string | number | boolean | null)[] = []\n if (data.name != null) { sets.push('name=?'); vals.push(data.name) }\n if (data.description != null) { sets.push('description=?'); vals.push(data.description) }\n if (sets.length > 0) { vals.push(id); await this.exec(`UPDATE roles SET ${sets.join(',')} WHERE id=?`, vals) }\n const rows = await this.q<RowRole>('SELECT * FROM roles WHERE id=?', [id])\n const row = rows[0]\n if (!row) throw new Error(`Role ${id} not found`)\n return mapRole(row)\n }\n\n async deleteRole(id: string): Promise<void> {\n await this.exec('DELETE FROM role_permissions WHERE role_id=?', [id])\n await this.exec('DELETE FROM user_roles WHERE role_id=?', [id])\n await this.exec('DELETE FROM roles WHERE id=?', [id])\n }\n\n async getAllPermissions(): Promise<Permission[]> {\n const rows = await this.q<RowPermission>('SELECT * FROM permissions ORDER BY name')\n return rows.map(mapPermission)\n }\n\n async getPermissionsForRole(roleId: string): Promise<Permission[]> {\n const rows = await this.q<RowPermission>(\n 'SELECT p.* FROM permissions p JOIN role_permissions rp ON p.id=rp.permission_id WHERE rp.role_id=?',\n [roleId],\n )\n return rows.map(mapPermission)\n }\n\n async getUserRoles(userId: string, tenantId?: string): Promise<Role[]> {\n const rows = tenantId\n ? await this.q<RowRole>(\n 'SELECT r.* FROM roles r JOIN user_roles ur ON r.id=ur.role_id WHERE ur.user_id=? AND ur.tenant_id=?',\n [userId, tenantId],\n )\n : await this.q<RowRole>(\n 'SELECT r.* FROM roles r JOIN user_roles ur ON r.id=ur.role_id WHERE ur.user_id=?',\n [userId],\n )\n return rows.map(mapRole)\n }\n\n async assignRole(userId: string, roleId: string, tenantId = 'default'): Promise<void> {\n await this.exec('INSERT IGNORE INTO user_roles (user_id, role_id, tenant_id) VALUES (?,?,?)', [userId, roleId, tenantId])\n }\n\n async revokeRole(userId: string, roleId: string, tenantId?: string): Promise<void> {\n if (tenantId) {\n await this.exec('DELETE FROM user_roles WHERE user_id=? AND role_id=? AND tenant_id=?', [userId, roleId, tenantId])\n } else {\n await this.exec('DELETE FROM user_roles WHERE user_id=? AND role_id=?', [userId, roleId])\n }\n }\n\n async assignPermissionToRole(roleId: string, permissionId: string): Promise<void> {\n await this.exec('INSERT IGNORE INTO role_permissions (role_id, permission_id) VALUES (?,?)', [roleId, permissionId])\n }\n\n async revokePermissionFromRole(roleId: string, permissionId: string): Promise<void> {\n await this.exec('DELETE FROM role_permissions WHERE role_id=? AND permission_id=?', [roleId, permissionId])\n }\n\n // ── Audit logs ────────────────────────────────────────────────────────────────\n\n async createLog(data: CreateAuditLogInput): Promise<void> {\n await this.exec(\n 'INSERT INTO audit_logs (id, tenant_id, user_id, action, resource_type, resource_id, old_data, new_data) VALUES (?,?,?,?,?,?,?,?)',\n [randomUUID(), data.tenantId, data.userId ?? null, data.action, data.resourceType,\n data.resourceId ?? null,\n data.oldData != null ? JSON.stringify(data.oldData) : null,\n data.newData != null ? JSON.stringify(data.newData) : null],\n )\n }\n\n async getLogs(filters: AuditFilters): Promise<AuditLog[]> {\n const { sql, params } = this.buildAuditQuery(filters)\n const page = filters.page ?? 1\n const limit = filters.limit ?? 50\n const rows = await this.q<RowAuditLog>(`${sql} ORDER BY created_at DESC LIMIT ? OFFSET ?`, [...params, limit, (page - 1) * limit])\n return rows.map(mapAuditLog)\n }\n\n async *streamAuditLogs(filters: AuditFilters): AsyncIterable<AuditLog> {\n const { sql, params } = this.buildAuditQuery(filters)\n const rows = await this.q<RowAuditLog>(`${sql} ORDER BY created_at ASC`, params)\n for (const r of rows) yield mapAuditLog(r)\n }\n\n private buildAuditQuery(f: AuditFilters): { sql: string; params: (string | number | boolean | null)[] } {\n let sql = 'SELECT * FROM audit_logs WHERE tenant_id=?'\n const params: (string | number | boolean | null)[] = [f.tenantId]\n if (f.action != null) { sql += ' AND action=?'; params.push(f.action) }\n if (f.resourceType != null) { sql += ' AND resource_type=?'; params.push(f.resourceType) }\n if (f.from != null) { sql += ' AND created_at>=?'; params.push(f.from) }\n if (f.to != null) { sql += ' AND created_at<=?'; params.push(f.to) }\n return { sql, params }\n }\n\n // ── Stats extensions ───────────────────────────────────────────────────────────\n\n async getCountries(tenantId: string): Promise<CountryStat[]> {\n const rows = await this.q<RowCountry>(\n `SELECT v.country, COUNT(*) AS count FROM consent_records cr\n JOIN visitors v ON v.visitor_id=cr.visitor_id\n WHERE cr.tenant_id=? AND v.country IS NOT NULL\n GROUP BY v.country ORDER BY count DESC LIMIT 50`,\n [tenantId],\n )\n return rows.map(r => ({ country: r.country, count: r.count }))\n }\n\n async getGpcStats(tenantId: string): Promise<GpcStats> {\n const [t] = await this.q<RowCount>('SELECT COUNT(*) AS total FROM consent_records WHERE tenant_id=?', [tenantId])\n const [d] = await this.q<RowCount>('SELECT COUNT(*) AS total FROM consent_records WHERE tenant_id=? AND gpc_detected=1', [tenantId])\n const total = t?.total ?? 0\n const detected = d?.total ?? 0\n return { detected, total, rate: total > 0 ? Math.round((detected / total) * 100) : 0 }\n }\n\n // ── Tenants ───────────────────────────────────────────────────────────────────\n\n async getTenants(): Promise<Tenant[]> {\n const rows = await this.q<RowTenant>('SELECT * FROM tenants ORDER BY name ASC', [])\n return rows.map(r => ({ id: r.id, name: r.name, slug: r.slug, createdAt: r.created_at, updatedAt: r.updated_at }))\n }\n\n // ── API Keys ──────────────────────────────────────────────────────────────────\n\n async createApiKey(data: CreateApiKeyInput): Promise<ApiKey> {\n const id = randomUUID()\n await this.exec(\n 'INSERT INTO api_keys (id, tenant_id, key_hash, name) VALUES (?,?,?,?)',\n [id, data.tenantId, data.keyHash, data.name],\n )\n const rows = await this.q<RowApiKey>('SELECT * FROM api_keys WHERE id=?', [id])\n const r = rows[0]\n if (!r) throw new Error('Failed to create API key')\n return { id: r.id, tenantId: r.tenant_id, keyHash: r.key_hash, name: r.name, isActive: r.is_active === 1, createdAt: r.created_at }\n }\n\n async getApiKeyByHash(keyHash: string): Promise<ApiKey | null> {\n const rows = await this.q<RowApiKey>('SELECT * FROM api_keys WHERE key_hash=? AND is_active=1', [keyHash])\n const r = rows[0]\n if (!r) return null\n return { id: r.id, tenantId: r.tenant_id, keyHash: r.key_hash, name: r.name, isActive: r.is_active === 1, createdAt: r.created_at }\n }\n\n async revokeApiKey(id: string): Promise<void> {\n await this.exec('UPDATE api_keys SET is_active=0 WHERE id=?', [id])\n }\n\n async getApiKeys(tenantId: string): Promise<ApiKey[]> {\n const rows = await this.q<RowApiKey>('SELECT * FROM api_keys WHERE tenant_id=? ORDER BY created_at DESC', [tenantId])\n return rows.map(r => ({ id: r.id, tenantId: r.tenant_id, keyHash: r.key_hash, name: r.name, isActive: r.is_active === 1, createdAt: r.created_at }))\n }\n\n async createTenant(data: CreateTenantInput): Promise<Tenant> {\n const id = randomUUID()\n const now = new Date().toISOString()\n await this.exec('INSERT INTO tenants (id, name, slug, created_at, updated_at) VALUES (?,?,?,?,?)', [id, data.name, data.slug, now, now])\n const rows = await this.q<RowTenant>('SELECT * FROM tenants WHERE id=?', [id])\n const r = rows[0]\n if (!r) throw new Error('Failed to create tenant')\n return { id: r.id, name: r.name, slug: r.slug, createdAt: r.created_at, updatedAt: r.updated_at }\n }\n\n async updateTenant(id: string, data: UpdateTenantInput): Promise<Tenant> {\n const now = new Date().toISOString()\n const sets: string[] = ['updated_at=?']\n const vals: (string | number)[] = [now]\n if (data.name != null) { sets.push('name=?'); vals.push(data.name) }\n if (data.slug != null) { sets.push('slug=?'); vals.push(data.slug) }\n vals.push(id)\n await this.exec(`UPDATE tenants SET ${sets.join(',')} WHERE id=?`, vals)\n const rows = await this.q<RowTenant>('SELECT * FROM tenants WHERE id=?', [id])\n const r = rows[0]\n if (!r) throw new Error(`Tenant ${id} not found`)\n return { id: r.id, name: r.name, slug: r.slug, createdAt: r.created_at, updatedAt: r.updated_at }\n }\n\n async deleteTenant(id: string): Promise<void> {\n await this.exec('DELETE FROM tenants WHERE id=?', [id])\n }\n\n async purgeExpiredConsents(olderThanDays: number): Promise<number> {\n const cutoff = new Date(Date.now() - olderThanDays * 86_400_000).toISOString()\n const visitorRows = await this.q<{ visitor_id: string } & RowDataPacket>(\n 'SELECT visitor_id FROM consent_records WHERE created_at < ?', [cutoff]\n )\n if (visitorRows.length === 0) return 0\n const ids = visitorRows.map(r => r.visitor_id)\n const placeholders = ids.map(() => '?').join(',')\n await this.exec(`DELETE FROM consent_history WHERE visitor_id IN (${placeholders})`, ids)\n await this.exec(`DELETE FROM consent_records WHERE visitor_id IN (${placeholders})`, ids)\n return ids.length\n }\n\n // Template methods — not yet implemented for MySQL adapter\n async createCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async updateCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async deleteCookieTemplate(): Promise<void> { throw new Error('Not implemented') }\n async getCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async getCookieTemplates(): Promise<never> { throw new Error('Not implemented') }\n async copyCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async createUITemplate(): Promise<never> { throw new Error('Not implemented') }\n async updateUITemplate(): Promise<never> { throw new Error('Not implemented') }\n async deleteUITemplate(): Promise<void> { throw new Error('Not implemented') }\n async getUITemplate(): Promise<never> { throw new Error('Not implemented') }\n async getUITemplates(): Promise<never> { throw new Error('Not implemented') }\n async copyUITemplate(): Promise<never> { throw new Error('Not implemented') }\n\n // Profile summary / analytics — not yet implemented for MySQL adapter\n async listProfilesSummary(): Promise<never[]> { return [] }\n async findProfilesUsingCookieTemplate(): Promise<never[]> { return [] }\n async findProfilesUsingUITemplate(): Promise<never[]> { return [] }\n async getOptInStats(): Promise<never> { throw new Error('Not implemented') }\n}\n","import type { Pool, PoolClient, QueryResult } from 'pg'\nimport { randomUUID } from '../../utils/crypto'\nimport { SEED_TENANT, SEED_PERMISSIONS, SEED_ROLES, SEED_ROLE_PERMISSIONS, SCHEMA_SQL_POSTGRES } from '../seed-data'\nimport type {\n StorageAdapter, StorageConfig, Profile, ProfileConfig,\n CreateProfileInput, UpdateProfileInput,\n ConsentDbRecord, ConsentHistoryEntry, ConsentValue, ConsentFilters,\n CreateConsentInput, UpdateConsentInput,\n Visitor, VisitorFilters, CreateVisitorInput, UpdateVisitorInput,\n AdminUser, CreateUserInput, UpdateUserInput,\n Role, CreateRoleInput, UpdateRoleInput,\n Permission, AuditLog, AuditFilters, CreateAuditLogInput,\n OverviewStats, CategoryStats, TimelineEntry,\n CountryStat, GpcStats, Tenant, ApiKey, CreateApiKeyInput,\n CreateTenantInput, UpdateTenantInput,\n} from '@consenti/types'\n\n// ── Raw row shapes ─────────────────────────────────────────────────────────────\n\ninterface RowProfile {\n id: string; tenant_id: string; name: string; default_locale: string\n version: number; profile_json: string\n created_at: string; updated_at: string\n}\ninterface RowConsent {\n id: string; tenant_id: string; visitor_id: string; profile_id: string\n profile_version: number; locale: string; consent_json: string\n gpc_detected: boolean; source: string; created_at: string; updated_at: string\n age_verified?: boolean; parental_consent_token?: string | null; tcf_string?: string | null\n}\ninterface RowConsentHistory {\n id: string; tenant_id: string; consent_record_id: string; visitor_id: string\n old_json: string | null; new_json: string; action: string; created_at: string\n}\ninterface RowVisitor {\n id: string; tenant_id: string; visitor_id: string\n country: string | null; region: string | null; city: string | null\n ip_hash: string | null; user_agent_hash: string | null\n first_seen: string; last_seen: string\n}\ninterface RowUser {\n id: string; tenant_id: string; name: string; email: string\n password_hash: string; is_active: boolean; created_at: string; updated_at: string\n totp_secret?: string | null; totp_enabled?: boolean\n}\ninterface RowRole { id: string; tenant_id: string; name: string; description: string | null }\ninterface RowPermission { id: string; name: string; description: string | null }\ninterface RowAuditLog {\n id: string; tenant_id: string; user_id: string | null; action: string\n resource_type: string; resource_id: string | null\n old_data: string | null; new_data: string | null; created_at: string\n}\ninterface RowCount { total: string }\ninterface RowStatus { status: string; count: string }\ninterface RowDateCount { date: string; count: string }\ninterface RowCookieStatus { cookie_id: string; status: string; count: string }\ninterface RowCountry { country: string; count: string }\ninterface RowApiKey { id: string; tenant_id: string; key_hash: string; name: string; is_active: boolean; created_at: string }\ninterface RowTenant { id: string; name: string; slug: string; created_at: string; updated_at: string }\n\n// ── Mappers ────────────────────────────────────────────────────────────────────\n\nfunction mapProfile(r: RowProfile): Profile {\n return {\n id: r.id, tenantId: r.tenant_id, name: r.name,\n defaultLocale: r.default_locale, version: r.version,\n profileJson: JSON.parse(r.profile_json) as ProfileConfig,\n createdAt: r.created_at, updatedAt: r.updated_at,\n }\n}\n\nfunction mapConsent(r: RowConsent): ConsentDbRecord {\n return {\n id: r.id, tenantId: r.tenant_id, visitorId: r.visitor_id, profileId: r.profile_id,\n profileVersion: r.profile_version, locale: r.locale,\n consentJson: JSON.parse(r.consent_json) as ConsentValue,\n gpcDetected: r.gpc_detected, source: r.source as ConsentDbRecord['source'],\n createdAt: r.created_at, updatedAt: r.updated_at,\n ...(r.age_verified != null ? { ageVerified: r.age_verified } : {}),\n ...(r.parental_consent_token != null ? { parentalConsentToken: r.parental_consent_token } : {}),\n ...(r.tcf_string != null ? { tcfString: r.tcf_string } : {}),\n }\n}\n\nfunction mapHistory(r: RowConsentHistory): ConsentHistoryEntry {\n return {\n id: r.id, tenantId: r.tenant_id, consentRecordId: r.consent_record_id,\n visitorId: r.visitor_id,\n oldJson: r.old_json ? JSON.parse(r.old_json) as ConsentValue : null,\n newJson: JSON.parse(r.new_json) as ConsentValue,\n action: r.action as ConsentHistoryEntry['action'], createdAt: r.created_at,\n }\n}\n\nfunction mapVisitor(r: RowVisitor): Visitor {\n return {\n id: r.id, tenantId: r.tenant_id, visitorId: r.visitor_id,\n ...(r.country != null ? { country: r.country } : {}),\n ...(r.region != null ? { region: r.region } : {}),\n ...(r.city != null ? { city: r.city } : {}),\n ...(r.ip_hash != null ? { ipHash: r.ip_hash } : {}),\n ...(r.user_agent_hash != null ? { userAgentHash: r.user_agent_hash } : {}),\n firstSeen: r.first_seen, lastSeen: r.last_seen,\n }\n}\n\nfunction mapUser(r: RowUser): AdminUser {\n return {\n id: r.id, tenantId: r.tenant_id, name: r.name, email: r.email,\n passwordHash: r.password_hash, isActive: r.is_active,\n createdAt: r.created_at, updatedAt: r.updated_at,\n totpEnabled: r.totp_enabled ?? false,\n ...(r.totp_secret != null ? { totpSecret: r.totp_secret } : {}),\n }\n}\n\nfunction mapRole(r: RowRole): Role {\n return {\n id: r.id, tenantId: r.tenant_id, name: r.name,\n ...(r.description != null ? { description: r.description } : {}),\n }\n}\n\nfunction mapPermission(r: RowPermission): Permission {\n return {\n id: r.id, name: r.name,\n ...(r.description != null ? { description: r.description } : {}),\n }\n}\n\nfunction mapAuditLog(r: RowAuditLog): AuditLog {\n return {\n id: r.id, tenantId: r.tenant_id, action: r.action, resourceType: r.resource_type,\n ...(r.user_id != null ? { userId: r.user_id } : {}),\n ...(r.resource_id != null ? { resourceId: r.resource_id } : {}),\n ...(r.old_data != null ? { oldData: JSON.parse(r.old_data) as unknown } : {}),\n ...(r.new_data != null ? { newData: JSON.parse(r.new_data) as unknown } : {}),\n createdAt: r.created_at,\n }\n}\n\n// ── Adapter ────────────────────────────────────────────────────────────────────\n\nexport class PostgreSQLAdapter implements StorageAdapter {\n private pool!: Pool\n\n constructor(private config: StorageConfig) { }\n\n private async q<T>(sql: string, params: (string | number | boolean | null)[] = []): Promise<T[]> {\n const result: QueryResult<T & object> = await this.pool.query<T & object>(sql, params as unknown[])\n return result.rows\n }\n\n async connect(): Promise<void> {\n type PgModule = { Pool: new (cfg: Record<string, unknown>) => Pool }\n const pg = (await import('pg')) as { default: PgModule }\n const PgPool = pg.default.Pool\n const cfg = this.config\n const poolCfg: Record<string, unknown> = cfg.uri\n ? { connectionString: cfg.uri }\n : {\n host: cfg.host ?? 'localhost',\n port: cfg.port ?? 5432,\n user: cfg.user ?? 'postgres',\n password: cfg.password ?? '',\n database: cfg.database ?? 'consenti',\n }\n this.pool = new PgPool(poolCfg)\n await this.migrate()\n }\n\n async disconnect(): Promise<void> {\n await this.pool.end()\n }\n\n async migrate(): Promise<void> {\n const client: PoolClient = await this.pool.connect()\n try {\n let version = 0\n try {\n const res = await client.query<{ version: number }>('SELECT version FROM schema_version ORDER BY version DESC LIMIT 1')\n version = res.rows[0]?.version ?? 0\n } catch {\n // schema_version doesn't exist — fresh install\n }\n\n if (version === 0) {\n await client.query('BEGIN')\n try {\n for (const stmt of SCHEMA_SQL_POSTGRES.split(';').map(s => s.trim()).filter(Boolean)) {\n await client.query(stmt)\n }\n await this.seedTx(client)\n await client.query('INSERT INTO schema_version (version) VALUES (2) ON CONFLICT DO NOTHING')\n await client.query('COMMIT')\n } catch (err) {\n await client.query('ROLLBACK')\n throw err\n }\n return\n }\n\n if (version < 2) {\n await client.query('BEGIN')\n try {\n const alters = [\n 'ALTER TABLE consent_records ADD COLUMN IF NOT EXISTS age_verified BOOLEAN NOT NULL DEFAULT FALSE',\n 'ALTER TABLE consent_records ADD COLUMN IF NOT EXISTS parental_consent_token TEXT',\n 'ALTER TABLE consent_records ADD COLUMN IF NOT EXISTS tcf_string TEXT',\n 'ALTER TABLE users ADD COLUMN IF NOT EXISTS totp_secret TEXT',\n 'ALTER TABLE users ADD COLUMN IF NOT EXISTS totp_enabled BOOLEAN NOT NULL DEFAULT FALSE',\n ]\n for (const stmt of alters) await client.query(stmt)\n await client.query('INSERT INTO schema_version (version) VALUES (2) ON CONFLICT DO NOTHING')\n await client.query('COMMIT')\n } catch (err) {\n await client.query('ROLLBACK')\n throw err\n }\n }\n\n if (version < 3) {\n await client.query('BEGIN')\n try {\n await client.query('ALTER TABLE user_roles ADD COLUMN IF NOT EXISTS tenant_id TEXT NOT NULL DEFAULT \\'default\\'')\n await client.query('INSERT INTO schema_version (version) VALUES (3) ON CONFLICT DO NOTHING')\n await client.query('COMMIT')\n } catch (err) {\n await client.query('ROLLBACK')\n throw err\n }\n }\n } finally {\n client.release()\n }\n }\n\n private async seedTx(client: PoolClient): Promise<void> {\n await client.query(\n 'INSERT INTO tenants (id, name, slug) VALUES ($1,$2,$3) ON CONFLICT DO NOTHING',\n [SEED_TENANT.id, SEED_TENANT.name, SEED_TENANT.slug],\n )\n for (const p of SEED_PERMISSIONS) {\n await client.query(\n 'INSERT INTO permissions (id, name, description) VALUES ($1,$2,$3) ON CONFLICT DO NOTHING',\n [p.id, p.name, p.description],\n )\n }\n for (const r of SEED_ROLES) {\n await client.query(\n 'INSERT INTO roles (id, tenant_id, name, description) VALUES ($1,$2,$3,$4) ON CONFLICT DO NOTHING',\n [r.id, r.tenantId, r.name, r.description],\n )\n }\n for (const { roleId, permissionId } of SEED_ROLE_PERMISSIONS) {\n await client.query(\n 'INSERT INTO role_permissions VALUES ($1,$2) ON CONFLICT DO NOTHING',\n [roleId, permissionId],\n )\n }\n }\n\n // ── Profiles ─────────────────────────────────────────────────────────────────\n\n async createProfile(data: CreateProfileInput): Promise<Profile> {\n const id = randomUUID()\n const rows = await this.q<RowProfile>(\n `INSERT INTO profiles (id, tenant_id, name, default_locale, profile_json)\n VALUES ($1,$2,$3,$4,$5::jsonb) RETURNING *`,\n [id, data.tenantId, data.name, data.defaultLocale, JSON.stringify(data.profileJson)],\n )\n const row = rows[0]\n if (!row) throw new Error('Profile creation failed')\n return mapProfile(row)\n }\n\n async updateProfile(id: string, data: UpdateProfileInput): Promise<Profile> {\n const sets: string[] = ['version = version + 1', 'updated_at = NOW()']\n const vals: (string | number | boolean | null)[] = []\n let idx = 1\n if (data.name != null) { sets.push(`name=$${idx++}`); vals.push(data.name) }\n if (data.defaultLocale != null) { sets.push(`default_locale=$${idx++}`); vals.push(data.defaultLocale) }\n if (data.profileJson != null) { sets.push(`profile_json=$${idx++}::jsonb`); vals.push(JSON.stringify(data.profileJson)) }\n vals.push(id)\n const rows = await this.q<RowProfile>(\n `UPDATE profiles SET ${sets.join(',')} WHERE id=$${idx} RETURNING *`,\n vals,\n )\n const row = rows[0]\n if (!row) throw new Error(`Profile ${id} not found`)\n return mapProfile(row)\n }\n\n async deleteProfile(id: string): Promise<void> {\n await this.q('DELETE FROM profiles WHERE id=$1', [id])\n }\n\n async getProfile(id: string): Promise<Profile | null> {\n const rows = await this.q<RowProfile>('SELECT * FROM profiles WHERE id=$1', [id])\n return rows[0] ? mapProfile(rows[0]) : null\n }\n\n async getProfiles(tenantId: string): Promise<Profile[]> {\n const rows = await this.q<RowProfile>('SELECT * FROM profiles WHERE tenant_id=$1 ORDER BY created_at DESC', [tenantId])\n return rows.map(mapProfile)\n }\n\n async findActiveProfileByComplianceGroup(tenantId: string, complianceGroup: string): Promise<Profile | null> {\n const profiles = await this.getProfiles(tenantId)\n return profiles.find(p => p.profileJson.complianceGroup === complianceGroup && p.profileJson.isActive) ?? null\n }\n\n // ── Consents ─────────────────────────────────────────────────────────────────\n\n async createConsent(data: CreateConsentInput): Promise<ConsentDbRecord> {\n const id = randomUUID()\n const rows = await this.q<RowConsent>(\n `INSERT INTO consent_records (id, tenant_id, visitor_id, profile_id, profile_version, locale, consent_json, gpc_detected, source)\n VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8,$9) RETURNING *`,\n [id, data.tenantId, data.visitorId, data.profileId, data.profileVersion,\n data.locale, JSON.stringify(data.consentJson), data.gpcDetected, data.source],\n )\n const row = rows[0]\n if (!row) throw new Error('Consent creation failed')\n await this.writeHistory(id, data.tenantId, data.visitorId, null, data.consentJson, 'created')\n return mapConsent(row)\n }\n\n async updateConsent(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord> {\n const existing = await this.getConsent(visitorId)\n if (!existing) throw new Error(`Consent for visitor ${visitorId} not found`)\n const sets: string[] = ['consent_json=$1::jsonb', 'updated_at=NOW()']\n const vals: (string | number | boolean | null)[] = [JSON.stringify(data.consentJson)]\n let idx = 2\n if (data.locale != null) { sets.push(`locale=$${idx++}`); vals.push(data.locale) }\n if (data.gpcDetected != null) { sets.push(`gpc_detected=$${idx++}`); vals.push(data.gpcDetected) }\n vals.push(visitorId)\n const rows = await this.q<RowConsent>(\n `UPDATE consent_records SET ${sets.join(',')} WHERE visitor_id=$${idx} RETURNING *`,\n vals,\n )\n const row = rows[0]\n if (!row) throw new Error(`Consent for visitor ${visitorId} not found`)\n await this.writeHistory(row.id, row.tenant_id, visitorId, existing.consentJson, data.consentJson, 'updated')\n return mapConsent(row)\n }\n\n async deleteConsent(visitorId: string): Promise<void> {\n await this.q('DELETE FROM consent_history WHERE visitor_id=$1', [visitorId])\n await this.q('DELETE FROM consent_records WHERE visitor_id=$1', [visitorId])\n }\n\n async getConsent(visitorId: string): Promise<ConsentDbRecord | null> {\n const rows = await this.q<RowConsent>('SELECT * FROM consent_records WHERE visitor_id=$1', [visitorId])\n return rows[0] ? mapConsent(rows[0]) : null\n }\n\n async getConsents(filters: ConsentFilters): Promise<ConsentDbRecord[]> {\n const { sql, params, nextIdx } = this.buildConsentQuery(filters)\n const page = filters.page ?? 1\n const limit = filters.limit ?? 50\n const rows = await this.q<RowConsent>(\n `${sql} ORDER BY created_at DESC LIMIT $${nextIdx} OFFSET $${nextIdx + 1}`,\n [...params, limit, (page - 1) * limit],\n )\n return rows.map(mapConsent)\n }\n\n async *streamConsents(filters: ConsentFilters): AsyncIterable<ConsentDbRecord> {\n const { sql, params } = this.buildConsentQuery(filters)\n const rows = await this.q<RowConsent>(`${sql} ORDER BY created_at ASC`, params)\n for (const r of rows) yield mapConsent(r)\n }\n\n private buildConsentQuery(f: ConsentFilters): { sql: string; params: (string | number | boolean | null)[]; nextIdx: number } {\n let sql = 'SELECT * FROM consent_records WHERE tenant_id=$1'\n const params: (string | number | boolean | null)[] = [f.tenantId]\n let idx = 2\n if (f.profileId != null) { sql += ` AND profile_id=$${idx++}`; params.push(f.profileId) }\n if (f.from != null) { sql += ` AND created_at>=$${idx++}`; params.push(f.from) }\n if (f.to != null) { sql += ` AND created_at<=$${idx++}`; params.push(f.to) }\n return { sql, params, nextIdx: idx }\n }\n\n private async writeHistory(\n consentRecordId: string, tenantId: string, visitorId: string,\n oldJson: ConsentValue | null, newJson: ConsentValue, action: string,\n ): Promise<void> {\n await this.q(\n `INSERT INTO consent_history (id, tenant_id, consent_record_id, visitor_id, old_json, new_json, action)\n VALUES ($1,$2,$3,$4,$5::jsonb,$6::jsonb,$7)`,\n [randomUUID(), tenantId, consentRecordId, visitorId,\n oldJson ? JSON.stringify(oldJson) : null, JSON.stringify(newJson), action],\n )\n }\n\n async getConsentHistory(visitorId: string): Promise<ConsentHistoryEntry[]> {\n const rows = await this.q<RowConsentHistory>(\n 'SELECT * FROM consent_history WHERE visitor_id=$1 ORDER BY created_at ASC',\n [visitorId],\n )\n return rows.map(mapHistory)\n }\n\n // ── Visitors ─────────────────────────────────────────────────────────────────\n\n async createVisitor(data: CreateVisitorInput): Promise<Visitor> {\n const id = randomUUID()\n const rows = await this.q<RowVisitor>(\n `INSERT INTO visitors (id, tenant_id, visitor_id, country, region, city, ip_hash, user_agent_hash)\n VALUES ($1,$2,$3,$4,$5,$6,$7,$8) RETURNING *`,\n [id, data.tenantId, data.visitorId,\n data.country ?? null, data.region ?? null, data.city ?? null,\n data.ipHash ?? null, data.userAgentHash ?? null],\n )\n const row = rows[0]\n if (!row) throw new Error('Visitor creation failed')\n return mapVisitor(row)\n }\n\n async updateVisitor(visitorId: string, data: UpdateVisitorInput): Promise<Visitor> {\n const sets: string[] = ['last_seen=NOW()']\n const vals: (string | number | boolean | null)[] = []\n let idx = 1\n if (data.country != null) { sets.push(`country=$${idx++}`); vals.push(data.country) }\n if (data.region != null) { sets.push(`region=$${idx++}`); vals.push(data.region) }\n if (data.city != null) { sets.push(`city=$${idx++}`); vals.push(data.city) }\n vals.push(visitorId)\n const rows = await this.q<RowVisitor>(\n `UPDATE visitors SET ${sets.join(',')} WHERE visitor_id=$${idx} RETURNING *`,\n vals,\n )\n const row = rows[0]\n if (!row) throw new Error(`Visitor ${visitorId} not found`)\n return mapVisitor(row)\n }\n\n async deleteVisitor(visitorId: string): Promise<void> {\n await this.q('DELETE FROM visitors WHERE visitor_id=$1', [visitorId])\n }\n\n async getVisitor(visitorId: string): Promise<Visitor | null> {\n const rows = await this.q<RowVisitor>('SELECT * FROM visitors WHERE visitor_id=$1', [visitorId])\n return rows[0] ? mapVisitor(rows[0]) : null\n }\n\n async getVisitors(filters: VisitorFilters): Promise<Visitor[]> {\n let sql = 'SELECT * FROM visitors WHERE tenant_id=$1'\n const params: (string | number | boolean | null)[] = [filters.tenantId]\n let idx = 2\n if (filters.from != null) { sql += ` AND first_seen>=$${idx++}`; params.push(filters.from) }\n if (filters.to != null) { sql += ` AND first_seen<=$${idx++}`; params.push(filters.to) }\n const page = filters.page ?? 1\n const limit = filters.limit ?? 50\n const rows = await this.q<RowVisitor>(\n `${sql} ORDER BY first_seen DESC LIMIT $${idx} OFFSET $${idx + 1}`,\n [...params, limit, (page - 1) * limit],\n )\n return rows.map(mapVisitor)\n }\n\n // ── Stats ─────────────────────────────────────────────────────────────────────\n\n async getOverviewStats(tenantId: string): Promise<OverviewStats> {\n const [[countRow], [gpcRow], [visitorRow]] = await Promise.all([\n this.q<RowCount>('SELECT COUNT(*)::int AS total FROM consent_records WHERE tenant_id=$1', [tenantId]),\n this.q<RowCount>('SELECT COUNT(*)::int AS total FROM consent_records WHERE tenant_id=$1 AND gpc_detected=true', [tenantId]),\n this.q<RowCount>('SELECT COUNT(*)::int AS total FROM visitors WHERE tenant_id=$1', [tenantId]),\n ])\n const total = Number(countRow?.total ?? 0)\n const gpcCount = Number(gpcRow?.total ?? 0)\n const visitors = Number(visitorRow?.total ?? 0)\n\n const statusRows = await this.q<RowStatus>(\n `SELECT val AS status, COUNT(*)::int AS count\n FROM consent_records cr,\n jsonb_each_text(cr.consent_json) AS kv(key, val)\n WHERE cr.tenant_id=$1\n GROUP BY val`,\n [tenantId],\n )\n let granted = 0, denied = 0, all = 0\n for (const r of statusRows) {\n all += Number(r.count)\n if (r.status === 'granted') granted = Number(r.count)\n if (r.status === 'denied') denied = Number(r.count)\n }\n return {\n totalConsents: total,\n acceptedPct: all > 0 ? Math.round((granted / all) * 100) : 0,\n rejectedPct: all > 0 ? Math.round((denied / all) * 100) : 0,\n totalVisitors: visitors,\n gpcDetectedCount: gpcCount,\n }\n }\n\n async getCategoryStats(tenantId: string): Promise<CategoryStats> {\n const rows = await this.q<RowCookieStatus>(\n `SELECT kv.key AS cookie_id, kv.val AS status, COUNT(*)::int AS count\n FROM consent_records cr,\n jsonb_each_text(cr.consent_json) AS kv(key, val)\n WHERE cr.tenant_id=$1\n GROUP BY kv.key, kv.val`,\n [tenantId],\n )\n const result: CategoryStats = {}\n for (const r of rows) {\n if (!result[r.cookie_id]) result[r.cookie_id] = { granted: 0, denied: 0, objected: 0 }\n const entry = result[r.cookie_id]\n if (entry) {\n if (r.status === 'granted') entry.granted += Number(r.count)\n if (r.status === 'denied') entry.denied += Number(r.count)\n if (r.status === 'objected') entry.objected += Number(r.count)\n }\n }\n return result\n }\n\n async getTimeline(tenantId: string, days = 30): Promise<TimelineEntry[]> {\n const from = new Date(Date.now() - days * 86400_000).toISOString()\n const rows = await this.q<RowDateCount>(\n `SELECT to_char(created_at, 'YYYY-MM-DD') AS date, COUNT(*)::int AS count\n FROM consent_records\n WHERE tenant_id=$1 AND created_at>=$2\n GROUP BY to_char(created_at, 'YYYY-MM-DD')\n ORDER BY date ASC`,\n [tenantId, from],\n )\n return rows.map(r => ({ date: r.date, count: Number(r.count) }))\n }\n\n // ── Users ─────────────────────────────────────────────────────────────────────\n\n async createUser(data: CreateUserInput): Promise<AdminUser> {\n const id = randomUUID()\n const rows = await this.q<RowUser>(\n 'INSERT INTO users (id, tenant_id, name, email, password_hash) VALUES ($1,$2,$3,$4,$5) RETURNING *',\n [id, data.tenantId, data.name, data.email, data.passwordHash],\n )\n const row = rows[0]\n if (!row) throw new Error('User creation failed')\n return mapUser(row)\n }\n\n async updateUser(id: string, data: UpdateUserInput): Promise<AdminUser> {\n const sets: string[] = ['updated_at=NOW()']\n const vals: (string | number | boolean | null)[] = []\n let idx = 1\n if (data.name != null) { sets.push(`name=$${idx++}`); vals.push(data.name) }\n if (data.email != null) { sets.push(`email=$${idx++}`); vals.push(data.email) }\n if (data.passwordHash != null) { sets.push(`password_hash=$${idx++}`); vals.push(data.passwordHash) }\n if (data.isActive != null) { sets.push(`is_active=$${idx++}`); vals.push(data.isActive) }\n vals.push(id)\n const rows = await this.q<RowUser>(\n `UPDATE users SET ${sets.join(',')} WHERE id=$${idx} RETURNING *`,\n vals,\n )\n const row = rows[0]\n if (!row) throw new Error(`User ${id} not found`)\n return mapUser(row)\n }\n\n async deleteUser(id: string): Promise<void> {\n await this.q('DELETE FROM user_roles WHERE user_id=$1', [id])\n await this.q('DELETE FROM users WHERE id=$1', [id])\n }\n\n async getUserById(id: string): Promise<AdminUser | null> {\n const rows = await this.q<RowUser>('SELECT * FROM users WHERE id=$1', [id])\n return rows[0] ? mapUser(rows[0]) : null\n }\n\n async getUserByEmail(email: string): Promise<AdminUser | null> {\n const rows = await this.q<RowUser>('SELECT * FROM users WHERE email=$1', [email])\n return rows[0] ? mapUser(rows[0]) : null\n }\n\n async getUsers(tenantId: string): Promise<AdminUser[]> {\n const rows = await this.q<RowUser>('SELECT * FROM users WHERE tenant_id=$1 ORDER BY created_at DESC', [tenantId])\n return rows.map(mapUser)\n }\n\n async countUsers(tenantId?: string): Promise<number> {\n const rows = tenantId\n ? await this.q<RowCount>('SELECT COUNT(*)::int AS total FROM users WHERE tenant_id=$1', [tenantId])\n : await this.q<RowCount>('SELECT COUNT(*)::int AS total FROM users')\n return Number(rows[0]?.total ?? 0)\n }\n\n // ── Roles & permissions ───────────────────────────────────────────────────────\n\n async getRoles(tenantId: string): Promise<Role[]> {\n const rows = await this.q<RowRole>('SELECT * FROM roles WHERE tenant_id=$1', [tenantId])\n return rows.map(mapRole)\n }\n\n async createRole(data: CreateRoleInput): Promise<Role> {\n const id = randomUUID()\n const rows = await this.q<RowRole>(\n 'INSERT INTO roles (id, tenant_id, name, description) VALUES ($1,$2,$3,$4) RETURNING *',\n [id, data.tenantId, data.name, data.description ?? null],\n )\n const row = rows[0]\n if (!row) throw new Error('Role creation failed')\n return mapRole(row)\n }\n\n async updateRole(id: string, data: UpdateRoleInput): Promise<Role> {\n const sets: string[] = []\n const vals: (string | number | boolean | null)[] = []\n let idx = 1\n if (data.name != null) { sets.push(`name=$${idx++}`); vals.push(data.name) }\n if (data.description != null) { sets.push(`description=$${idx++}`); vals.push(data.description) }\n if (sets.length === 0) {\n const rows = await this.q<RowRole>('SELECT * FROM roles WHERE id=$1', [id])\n const row = rows[0]\n if (!row) throw new Error(`Role ${id} not found`)\n return mapRole(row)\n }\n vals.push(id)\n const rows = await this.q<RowRole>(`UPDATE roles SET ${sets.join(',')} WHERE id=$${idx} RETURNING *`, vals)\n const row = rows[0]\n if (!row) throw new Error(`Role ${id} not found`)\n return mapRole(row)\n }\n\n async deleteRole(id: string): Promise<void> {\n await this.q('DELETE FROM role_permissions WHERE role_id=$1', [id])\n await this.q('DELETE FROM user_roles WHERE role_id=$1', [id])\n await this.q('DELETE FROM roles WHERE id=$1', [id])\n }\n\n async getAllPermissions(): Promise<Permission[]> {\n const rows = await this.q<RowPermission>('SELECT * FROM permissions ORDER BY name')\n return rows.map(mapPermission)\n }\n\n async getPermissionsForRole(roleId: string): Promise<Permission[]> {\n const rows = await this.q<RowPermission>(\n 'SELECT p.* FROM permissions p JOIN role_permissions rp ON p.id=rp.permission_id WHERE rp.role_id=$1',\n [roleId],\n )\n return rows.map(mapPermission)\n }\n\n async getUserRoles(userId: string, tenantId?: string): Promise<Role[]> {\n const rows = tenantId\n ? await this.q<RowRole>(\n 'SELECT r.* FROM roles r JOIN user_roles ur ON r.id=ur.role_id WHERE ur.user_id=$1 AND ur.tenant_id=$2',\n [userId, tenantId],\n )\n : await this.q<RowRole>(\n 'SELECT r.* FROM roles r JOIN user_roles ur ON r.id=ur.role_id WHERE ur.user_id=$1',\n [userId],\n )\n return rows.map(mapRole)\n }\n\n async assignRole(userId: string, roleId: string, tenantId = 'default'): Promise<void> {\n await this.q('INSERT INTO user_roles (user_id, role_id, tenant_id) VALUES ($1,$2,$3) ON CONFLICT DO NOTHING', [userId, roleId, tenantId])\n }\n\n async revokeRole(userId: string, roleId: string, tenantId?: string): Promise<void> {\n if (tenantId) {\n await this.q('DELETE FROM user_roles WHERE user_id=$1 AND role_id=$2 AND tenant_id=$3', [userId, roleId, tenantId])\n } else {\n await this.q('DELETE FROM user_roles WHERE user_id=$1 AND role_id=$2', [userId, roleId])\n }\n }\n\n async assignPermissionToRole(roleId: string, permissionId: string): Promise<void> {\n await this.q('INSERT INTO role_permissions (role_id, permission_id) VALUES ($1,$2) ON CONFLICT DO NOTHING', [roleId, permissionId])\n }\n\n async revokePermissionFromRole(roleId: string, permissionId: string): Promise<void> {\n await this.q('DELETE FROM role_permissions WHERE role_id=$1 AND permission_id=$2', [roleId, permissionId])\n }\n\n // ── Audit logs ────────────────────────────────────────────────────────────────\n\n async createLog(data: CreateAuditLogInput): Promise<void> {\n await this.q(\n `INSERT INTO audit_logs (id, tenant_id, user_id, action, resource_type, resource_id, old_data, new_data)\n VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8::jsonb)`,\n [randomUUID(), data.tenantId, data.userId ?? null, data.action, data.resourceType,\n data.resourceId ?? null,\n data.oldData != null ? JSON.stringify(data.oldData) : null,\n data.newData != null ? JSON.stringify(data.newData) : null],\n )\n }\n\n async getLogs(filters: AuditFilters): Promise<AuditLog[]> {\n const { sql, params, nextIdx } = this.buildAuditQuery(filters)\n const page = filters.page ?? 1\n const limit = filters.limit ?? 50\n const rows = await this.q<RowAuditLog>(\n `${sql} ORDER BY created_at DESC LIMIT $${nextIdx} OFFSET $${nextIdx + 1}`,\n [...params, limit, (page - 1) * limit],\n )\n return rows.map(mapAuditLog)\n }\n\n async *streamAuditLogs(filters: AuditFilters): AsyncIterable<AuditLog> {\n const { sql, params } = this.buildAuditQuery(filters)\n const rows = await this.q<RowAuditLog>(`${sql} ORDER BY created_at ASC`, params)\n for (const r of rows) yield mapAuditLog(r)\n }\n\n private buildAuditQuery(f: AuditFilters): { sql: string; params: (string | number | boolean | null)[]; nextIdx: number } {\n let sql = 'SELECT * FROM audit_logs WHERE tenant_id=$1'\n const params: (string | number | boolean | null)[] = [f.tenantId]\n let idx = 2\n if (f.action != null) { sql += ` AND action=$${idx++}`; params.push(f.action) }\n if (f.resourceType != null) { sql += ` AND resource_type=$${idx++}`; params.push(f.resourceType) }\n if (f.from != null) { sql += ` AND created_at>=$${idx++}`; params.push(f.from) }\n if (f.to != null) { sql += ` AND created_at<=$${idx++}`; params.push(f.to) }\n return { sql, params, nextIdx: idx }\n }\n\n // ── Stats extensions ───────────────────────────────────────────────────────────\n\n async getCountries(tenantId: string): Promise<CountryStat[]> {\n const rows = await this.q<RowCountry>(\n `SELECT v.country, COUNT(*)::int AS count FROM consent_records cr\n JOIN visitors v ON v.visitor_id=cr.visitor_id\n WHERE cr.tenant_id=$1 AND v.country IS NOT NULL\n GROUP BY v.country ORDER BY count DESC LIMIT 50`,\n [tenantId],\n )\n return rows.map(r => ({ country: r.country, count: Number(r.count) }))\n }\n\n async getGpcStats(tenantId: string): Promise<GpcStats> {\n const [t] = await this.q<RowCount>('SELECT COUNT(*)::int AS total FROM consent_records WHERE tenant_id=$1', [tenantId])\n const [d] = await this.q<RowCount>('SELECT COUNT(*)::int AS total FROM consent_records WHERE tenant_id=$1 AND gpc_detected=TRUE', [tenantId])\n const total = Number(t?.total ?? 0)\n const detected = Number(d?.total ?? 0)\n return { detected, total, rate: total > 0 ? Math.round((detected / total) * 100) : 0 }\n }\n\n // ── Tenants ───────────────────────────────────────────────────────────────────\n\n async getTenants(): Promise<Tenant[]> {\n const rows = await this.q<RowTenant>('SELECT * FROM tenants ORDER BY name ASC', [])\n return rows.map(r => ({ id: r.id, name: r.name, slug: r.slug, createdAt: r.created_at, updatedAt: r.updated_at }))\n }\n\n // ── API Keys ──────────────────────────────────────────────────────────────────\n\n async createApiKey(data: CreateApiKeyInput): Promise<ApiKey> {\n const id = randomUUID()\n const rows = await this.q<RowApiKey>(\n 'INSERT INTO api_keys (id, tenant_id, key_hash, name) VALUES ($1,$2,$3,$4) RETURNING *',\n [id, data.tenantId, data.keyHash, data.name],\n )\n const r = rows[0]\n if (!r) throw new Error('Failed to create API key')\n return { id: r.id, tenantId: r.tenant_id, keyHash: r.key_hash, name: r.name, isActive: r.is_active, createdAt: r.created_at }\n }\n\n async getApiKeyByHash(keyHash: string): Promise<ApiKey | null> {\n const rows = await this.q<RowApiKey>('SELECT * FROM api_keys WHERE key_hash=$1 AND is_active=TRUE', [keyHash])\n const r = rows[0]\n if (!r) return null\n return { id: r.id, tenantId: r.tenant_id, keyHash: r.key_hash, name: r.name, isActive: r.is_active, createdAt: r.created_at }\n }\n\n async revokeApiKey(id: string): Promise<void> {\n await this.q('UPDATE api_keys SET is_active=FALSE WHERE id=$1', [id])\n }\n\n async getApiKeys(tenantId: string): Promise<ApiKey[]> {\n const rows = await this.q<RowApiKey>('SELECT * FROM api_keys WHERE tenant_id=$1 ORDER BY created_at DESC', [tenantId])\n return rows.map(r => ({ id: r.id, tenantId: r.tenant_id, keyHash: r.key_hash, name: r.name, isActive: r.is_active, createdAt: r.created_at }))\n }\n\n async createTenant(data: CreateTenantInput): Promise<Tenant> {\n const id = randomUUID()\n const now = new Date().toISOString()\n const rows = await this.q<RowTenant>(\n 'INSERT INTO tenants (id, name, slug, created_at, updated_at) VALUES ($1,$2,$3,$4,$5) RETURNING *',\n [id, data.name, data.slug, now, now],\n )\n const r = rows[0]\n if (!r) throw new Error('Failed to create tenant')\n return { id: r.id, name: r.name, slug: r.slug, createdAt: r.created_at, updatedAt: r.updated_at }\n }\n\n async updateTenant(id: string, data: UpdateTenantInput): Promise<Tenant> {\n const now = new Date().toISOString()\n const sets: string[] = ['updated_at=$1']\n const vals: (string | number)[] = [now]\n let idx = 2\n if (data.name != null) { sets.push(`name=$${idx++}`); vals.push(data.name) }\n if (data.slug != null) { sets.push(`slug=$${idx++}`); vals.push(data.slug) }\n vals.push(id)\n const rows = await this.q<RowTenant>(\n `UPDATE tenants SET ${sets.join(',')} WHERE id=$${idx} RETURNING *`, vals,\n )\n const r = rows[0]\n if (!r) throw new Error(`Tenant ${id} not found`)\n return { id: r.id, name: r.name, slug: r.slug, createdAt: r.created_at, updatedAt: r.updated_at }\n }\n\n async deleteTenant(id: string): Promise<void> {\n await this.q('DELETE FROM tenants WHERE id=$1', [id])\n }\n\n async purgeExpiredConsents(olderThanDays: number): Promise<number> {\n const cutoff = new Date(Date.now() - olderThanDays * 86_400_000).toISOString()\n const visitorRows = await this.q<{ visitor_id: string }>(\n 'SELECT visitor_id FROM consent_records WHERE created_at < $1', [cutoff]\n )\n if (visitorRows.length === 0) return 0\n const ids = visitorRows.map(r => r.visitor_id)\n const placeholders = ids.map((_: string, i: number) => `$${i + 1}`).join(',')\n await this.q(`DELETE FROM consent_history WHERE visitor_id IN (${placeholders})`, ids)\n await this.q(`DELETE FROM consent_records WHERE visitor_id IN (${placeholders})`, ids)\n return ids.length\n }\n\n // Template methods — not yet implemented for PostgreSQL adapter\n async createCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async updateCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async deleteCookieTemplate(): Promise<void> { throw new Error('Not implemented') }\n async getCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async getCookieTemplates(): Promise<never> { throw new Error('Not implemented') }\n async copyCookieTemplate(): Promise<never> { throw new Error('Not implemented') }\n async createUITemplate(): Promise<never> { throw new Error('Not implemented') }\n async updateUITemplate(): Promise<never> { throw new Error('Not implemented') }\n async deleteUITemplate(): Promise<void> { throw new Error('Not implemented') }\n async getUITemplate(): Promise<never> { throw new Error('Not implemented') }\n async getUITemplates(): Promise<never> { throw new Error('Not implemented') }\n async copyUITemplate(): Promise<never> { throw new Error('Not implemented') }\n\n // Profile summary / analytics — not yet implemented for PostgreSQL adapter\n async listProfilesSummary(): Promise<never[]> { return [] }\n async findProfilesUsingCookieTemplate(): Promise<never[]> { return [] }\n async findProfilesUsingUITemplate(): Promise<never[]> { return [] }\n async getOptInStats(): Promise<never> { throw new Error('Not implemented') }\n}\n","import { readFile, writeFile, rename, mkdir } from 'node:fs/promises'\nimport { randomUUID } from 'node:crypto'\nimport type {\n StorageAdapter,\n StorageConfig,\n Profile,\n ProfileConfig,\n ProfileSummary,\n OptInStats,\n OptInFilters,\n ComplianceGroupId,\n CreateProfileInput,\n UpdateProfileInput,\n ConsentDbRecord,\n ConsentHistoryEntry,\n ConsentValue,\n CreateConsentInput,\n UpdateConsentInput,\n ConsentFilters,\n Visitor,\n VisitorFilters,\n CreateVisitorInput,\n UpdateVisitorInput,\n AdminUser,\n CreateUserInput,\n UpdateUserInput,\n Role,\n CreateRoleInput,\n UpdateRoleInput,\n Permission,\n AuditLog,\n AuditFilters,\n CreateAuditLogInput,\n OverviewStats,\n CategoryStats,\n TimelineEntry,\n CountryStat,\n GpcStats,\n Tenant,\n ApiKey,\n CreateApiKeyInput,\n CreateTenantInput,\n UpdateTenantInput,\n ServerCookieTemplate,\n ServerUITemplate,\n CreateCookieTemplateInput,\n UpdateCookieTemplateInput,\n CreateUITemplateInput,\n UpdateUITemplateInput,\n} from '@consenti/types'\nimport { resolveStoragePaths } from '../../utils/storage-path'\nimport {\n SEED_TENANT,\n SEED_PERMISSIONS,\n SEED_ROLES,\n SEED_ROLE_PERMISSIONS,\n} from '../seed-data'\n\nconst MAX_PAGE_SIZE = 500\n\ninterface UserRole { userId: string; roleId: string; tenantId: string }\ninterface RolePermission { roleId: string; permissionId: string }\n\ninterface JsonDb {\n _version: number\n tenants: Tenant[]\n profiles: Profile[]\n consents: ConsentDbRecord[]\n consent_history: ConsentHistoryEntry[]\n visitors: Visitor[]\n users: AdminUser[]\n roles: Role[]\n permissions: Permission[]\n user_roles: UserRole[]\n role_permissions: RolePermission[]\n audit_logs: AuditLog[]\n cookie_templates: ServerCookieTemplate[]\n ui_templates: ServerUITemplate[]\n api_keys: ApiKey[]\n}\n\nfunction emptyDb(): JsonDb {\n return {\n _version: 1,\n tenants: [],\n profiles: [],\n consents: [],\n consent_history: [],\n visitors: [],\n users: [],\n roles: [],\n permissions: [],\n user_roles: [],\n role_permissions: [],\n audit_logs: [],\n cookie_templates: [],\n ui_templates: [],\n api_keys: [],\n }\n}\n\nfunction randomProfileId(): string {\n return `prof_${randomUUID().replace(/-/g, '')}`\n}\n\nfunction page<T>(arr: T[], pageNum: number, limit: number): T[] {\n const l = Math.min(limit, MAX_PAGE_SIZE)\n const offset = (pageNum - 1) * l\n return arr.slice(offset, offset + l)\n}\n\nexport class JsonFileAdapter implements StorageAdapter {\n private db: JsonDb = emptyDb()\n private filePath = ''\n // Steno-equivalent: serialised writes via promise chain.\n // Old settled promises are GC'd on reassignment — no memory leak.\n private writeQueue: Promise<void> = Promise.resolve()\n\n constructor(private config: StorageConfig) {}\n\n private scheduleWrite(): void {\n this.writeQueue = this.writeQueue\n .then(async () => {\n await mkdir(this.filePath.replace(/\\/[^/]+$/, ''), { recursive: true })\n const tmp = `${this.filePath}.tmp`\n await writeFile(tmp, JSON.stringify(this.db), 'utf8')\n await rename(tmp, this.filePath)\n })\n .catch((err: unknown) => { console.warn('[Consenti] JSON store write failed:', err) })\n }\n\n async connect(): Promise<void> {\n const { dbPath } = resolveStoragePaths(this.config.path ?? './consenti-data', 'json')\n this.filePath = dbPath\n try {\n const raw = await readFile(this.filePath, 'utf8')\n this.db = JSON.parse(raw) as JsonDb\n } catch {\n this.db = emptyDb()\n }\n await this.migrate()\n }\n\n async disconnect(): Promise<void> {\n await this.writeQueue\n }\n\n async migrate(): Promise<void> {\n this.seed()\n }\n\n private seed(): void {\n const now = new Date().toISOString()\n const { id, name, slug } = SEED_TENANT\n if (!this.db.tenants.find(t => t.id === id)) {\n this.db.tenants.push({ id, name, slug, createdAt: now, updatedAt: now })\n }\n for (const p of SEED_PERMISSIONS) {\n if (!this.db.permissions.find(x => x.id === p.id)) {\n this.db.permissions.push({ id: p.id, name: p.name, description: p.description })\n }\n }\n for (const r of SEED_ROLES) {\n if (!this.db.roles.find(x => x.id === r.id)) {\n this.db.roles.push({ id: r.id, tenantId: r.tenantId, name: r.name, description: r.description })\n }\n }\n for (const rp of SEED_ROLE_PERMISSIONS) {\n if (!this.db.role_permissions.find(x => x.roleId === rp.roleId && x.permissionId === rp.permissionId)) {\n this.db.role_permissions.push(rp)\n }\n }\n this.scheduleWrite()\n }\n\n // ── Profiles ──────────────────────────────────────────────────────────────\n\n async createProfile(data: CreateProfileInput): Promise<Profile> {\n const now = new Date().toISOString()\n const profile: Profile = {\n id: randomProfileId(),\n tenantId: data.tenantId,\n name: data.name,\n defaultLocale: data.defaultLocale,\n version: 1,\n profileJson: data.profileJson as ProfileConfig,\n createdAt: now,\n updatedAt: now,\n }\n this.db.profiles.push(profile)\n this.scheduleWrite()\n return profile\n }\n\n async updateProfile(id: string, data: UpdateProfileInput): Promise<Profile> {\n const idx = this.db.profiles.findIndex(p => p.id === id)\n if (idx === -1) throw new Error(`Profile ${id} not found`)\n const existing = this.db.profiles[idx]!\n const updated: Profile = {\n ...existing,\n ...(data.name != null && { name: data.name }),\n ...(data.defaultLocale != null && { defaultLocale: data.defaultLocale }),\n ...(data.profileJson != null && { profileJson: data.profileJson as ProfileConfig }),\n version: existing.version + 1,\n updatedAt: new Date().toISOString(),\n }\n this.db.profiles[idx] = updated\n this.scheduleWrite()\n return updated\n }\n\n async deleteProfile(id: string): Promise<void> {\n this.db.profiles = this.db.profiles.filter(p => p.id !== id)\n this.scheduleWrite()\n }\n\n async getProfile(id: string): Promise<Profile | null> {\n return this.db.profiles.find(p => p.id === id) ?? null\n }\n\n async getProfiles(tenantId: string): Promise<Profile[]> {\n return this.db.profiles.filter(p => p.tenantId === tenantId)\n .sort((a, b) => a.createdAt.localeCompare(b.createdAt))\n }\n\n async findActiveProfileByComplianceGroup(tenantId: string, complianceGroup: string): Promise<Profile | null> {\n return this.db.profiles.find(p =>\n p.tenantId === tenantId &&\n p.profileJson.complianceGroup === complianceGroup &&\n p.profileJson.isActive\n ) ?? null\n }\n\n // ── Consents ──────────────────────────────────────────────────────────────\n\n async createConsent(data: CreateConsentInput): Promise<ConsentDbRecord> {\n const now = new Date().toISOString()\n const id = randomUUID()\n const record: ConsentDbRecord = {\n id,\n tenantId: data.tenantId,\n visitorId: data.visitorId,\n profileId: data.profileId,\n profileVersion: data.profileVersion,\n locale: data.locale,\n consentJson: data.consentJson as ConsentValue,\n gpcDetected: data.gpcDetected ?? false,\n source: data.source as ConsentDbRecord['source'],\n createdAt: now,\n updatedAt: now,\n }\n this.db.consents.push(record)\n this.db.consent_history.push({\n id: randomUUID(),\n tenantId: data.tenantId,\n consentRecordId: id,\n visitorId: data.visitorId,\n oldJson: null,\n newJson: data.consentJson as ConsentValue,\n action: 'created',\n createdAt: now,\n })\n this.scheduleWrite()\n return record\n }\n\n async updateConsent(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord> {\n const idx = this.db.consents.findIndex(c => c.visitorId === visitorId)\n if (idx === -1) throw new Error(`Consent for visitor ${visitorId} not found`)\n const existing = this.db.consents[idx]!\n const now = new Date().toISOString()\n const updated: ConsentDbRecord = {\n ...existing,\n consentJson: data.consentJson as ConsentValue,\n ...(data.locale != null && { locale: data.locale }),\n ...(data.gpcDetected != null && { gpcDetected: data.gpcDetected }),\n updatedAt: now,\n }\n this.db.consents[idx] = updated\n this.db.consent_history.push({\n id: randomUUID(),\n tenantId: existing.tenantId,\n consentRecordId: existing.id,\n visitorId,\n oldJson: existing.consentJson,\n newJson: data.consentJson as ConsentValue,\n action: 'updated',\n createdAt: now,\n })\n this.scheduleWrite()\n return updated\n }\n\n async deleteConsent(visitorId: string): Promise<void> {\n this.db.consent_history = this.db.consent_history.filter(h => h.visitorId !== visitorId)\n this.db.consents = this.db.consents.filter(c => c.visitorId !== visitorId)\n this.scheduleWrite()\n }\n\n async getConsent(visitorId: string): Promise<ConsentDbRecord | null> {\n return this.db.consents.find(c => c.visitorId === visitorId) ?? null\n }\n\n async getConsents(filters: ConsentFilters): Promise<ConsentDbRecord[]> {\n let rows = this.db.consents.filter(c => c.tenantId === filters.tenantId)\n if (filters.profileId) rows = rows.filter(c => c.profileId === filters.profileId)\n if (filters.from) rows = rows.filter(c => c.createdAt >= filters.from!)\n if (filters.to) rows = rows.filter(c => c.createdAt <= filters.to!)\n rows.sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n return page(rows, filters.page ?? 1, filters.limit ?? 50)\n }\n\n async *streamConsents(filters: ConsentFilters): AsyncIterable<ConsentDbRecord> {\n for (const c of this.db.consents.filter(c => c.tenantId === filters.tenantId)) yield c\n }\n\n async getConsentHistory(visitorId: string): Promise<ConsentHistoryEntry[]> {\n return this.db.consent_history\n .filter(h => h.visitorId === visitorId)\n .sort((a, b) => a.createdAt.localeCompare(b.createdAt))\n }\n\n // ── Visitors ──────────────────────────────────────────────────────────────\n\n async createVisitor(data: CreateVisitorInput): Promise<Visitor> {\n const now = new Date().toISOString()\n const visitor: Visitor = {\n id: randomUUID(),\n tenantId: data.tenantId,\n visitorId: data.visitorId,\n firstSeen: now,\n lastSeen: now,\n ...(data.country != null && { country: data.country }),\n ...(data.region != null && { region: data.region }),\n ...(data.city != null && { city: data.city }),\n ...(data.ipHash != null && { ipHash: data.ipHash }),\n ...(data.userAgentHash != null && { userAgentHash: data.userAgentHash }),\n }\n this.db.visitors.push(visitor)\n this.scheduleWrite()\n return visitor\n }\n\n async updateVisitor(visitorId: string, data: UpdateVisitorInput): Promise<Visitor> {\n const idx = this.db.visitors.findIndex(v => v.visitorId === visitorId)\n if (idx === -1) throw new Error(`Visitor ${visitorId} not found`)\n const existing = this.db.visitors[idx]!\n const updated: Visitor = {\n ...existing,\n lastSeen: data.lastSeen ?? new Date().toISOString(),\n ...(data.country != null && { country: data.country }),\n ...(data.region != null && { region: data.region }),\n ...(data.city != null && { city: data.city }),\n }\n this.db.visitors[idx] = updated\n this.scheduleWrite()\n return updated\n }\n\n async deleteVisitor(visitorId: string): Promise<void> {\n this.db.visitors = this.db.visitors.filter(v => v.visitorId !== visitorId)\n this.scheduleWrite()\n }\n\n async getVisitor(visitorId: string): Promise<Visitor | null> {\n return this.db.visitors.find(v => v.visitorId === visitorId) ?? null\n }\n\n async getVisitors(filters: VisitorFilters): Promise<Visitor[]> {\n let rows = this.db.visitors.filter(v => v.tenantId === filters.tenantId)\n if (filters.from) rows = rows.filter(v => v.firstSeen >= filters.from!)\n if (filters.to) rows = rows.filter(v => v.firstSeen <= filters.to!)\n rows.sort((a, b) => b.lastSeen.localeCompare(a.lastSeen))\n return page(rows, filters.page ?? 1, filters.limit ?? 50)\n }\n\n // ── Users ──────────────────────────────────────────────────────────────────\n\n async createUser(data: CreateUserInput): Promise<AdminUser> {\n const now = new Date().toISOString()\n const user: AdminUser = {\n id: randomUUID(),\n tenantId: data.tenantId,\n name: data.name,\n email: data.email,\n passwordHash: data.passwordHash,\n isActive: true,\n allowedTenants: data.allowedTenants ?? [],\n createdAt: now,\n updatedAt: now,\n }\n this.db.users.push(user)\n this.scheduleWrite()\n return user\n }\n\n async updateUser(id: string, data: UpdateUserInput): Promise<AdminUser> {\n const idx = this.db.users.findIndex(u => u.id === id)\n if (idx === -1) throw new Error(`User ${id} not found`)\n const existing = this.db.users[idx]!\n const updated: AdminUser = {\n ...existing,\n ...(data.name != null && { name: data.name }),\n ...(data.email != null && { email: data.email }),\n ...(data.passwordHash != null && { passwordHash: data.passwordHash }),\n ...(data.isActive != null && { isActive: data.isActive }),\n ...('totpSecret' in data && data.totpSecret != null && { totpSecret: data.totpSecret }),\n ...(data.totpEnabled != null && { totpEnabled: data.totpEnabled }),\n ...('allowedTenants' in data && { allowedTenants: data.allowedTenants ?? [] }),\n updatedAt: new Date().toISOString(),\n }\n this.db.users[idx] = updated\n this.scheduleWrite()\n return updated\n }\n\n async deleteUser(id: string): Promise<void> {\n this.db.user_roles = this.db.user_roles.filter(ur => ur.userId !== id)\n this.db.users = this.db.users.filter(u => u.id !== id)\n this.scheduleWrite()\n }\n\n async getUserById(id: string): Promise<AdminUser | null> {\n return this.db.users.find(u => u.id === id) ?? null\n }\n\n async getUserByEmail(email: string): Promise<AdminUser | null> {\n return this.db.users.find(u => u.email === email) ?? null\n }\n\n async getUsers(tenantId: string): Promise<AdminUser[]> {\n return this.db.users.filter(u => u.tenantId === tenantId)\n .sort((a, b) => a.createdAt.localeCompare(b.createdAt))\n }\n\n async countUsers(tenantId?: string): Promise<number> {\n return tenantId\n ? this.db.users.filter(u => u.tenantId === tenantId).length\n : this.db.users.length\n }\n\n // ── Roles & Permissions ────────────────────────────────────────────────────\n\n async getRoles(tenantId: string): Promise<Role[]> {\n return this.db.roles.filter(r => r.tenantId === tenantId)\n }\n\n async createRole(data: CreateRoleInput): Promise<Role> {\n const role: Role = {\n id: randomUUID(),\n tenantId: data.tenantId,\n name: data.name,\n ...(data.description != null && { description: data.description }),\n }\n this.db.roles.push(role)\n this.scheduleWrite()\n return role\n }\n\n async updateRole(id: string, data: UpdateRoleInput): Promise<Role> {\n const idx = this.db.roles.findIndex(r => r.id === id)\n if (idx === -1) throw new Error(`Role ${id} not found`)\n const updated: Role = {\n ...this.db.roles[idx]!,\n ...(data.name != null && { name: data.name }),\n ...(data.description != null && { description: data.description }),\n }\n this.db.roles[idx] = updated\n this.scheduleWrite()\n return updated\n }\n\n async deleteRole(id: string): Promise<void> {\n this.db.role_permissions = this.db.role_permissions.filter(rp => rp.roleId !== id)\n this.db.user_roles = this.db.user_roles.filter(ur => ur.roleId !== id)\n this.db.roles = this.db.roles.filter(r => r.id !== id)\n this.scheduleWrite()\n }\n\n async getAllPermissions(): Promise<Permission[]> {\n return [...this.db.permissions].sort((a, b) => a.name.localeCompare(b.name))\n }\n\n async getPermissionsForRole(roleId: string): Promise<Permission[]> {\n const permIds = new Set(\n this.db.role_permissions.filter(rp => rp.roleId === roleId).map(rp => rp.permissionId)\n )\n return this.db.permissions.filter(p => permIds.has(p.id))\n }\n\n async getUserRoles(userId: string, tenantId?: string): Promise<Role[]> {\n let urs = this.db.user_roles.filter(ur => ur.userId === userId)\n if (tenantId) urs = urs.filter(ur => ur.tenantId === tenantId)\n const roleIds = new Set(urs.map(ur => ur.roleId))\n return this.db.roles.filter(r => roleIds.has(r.id))\n }\n\n async assignRole(userId: string, roleId: string, tenantId = 'default'): Promise<void> {\n if (!this.db.user_roles.find(ur => ur.userId === userId && ur.roleId === roleId && ur.tenantId === tenantId)) {\n this.db.user_roles.push({ userId, roleId, tenantId })\n this.scheduleWrite()\n }\n }\n\n async revokeRole(userId: string, roleId: string, tenantId?: string): Promise<void> {\n this.db.user_roles = this.db.user_roles.filter(ur =>\n !(ur.userId === userId && ur.roleId === roleId && (tenantId == null || ur.tenantId === tenantId))\n )\n this.scheduleWrite()\n }\n\n async assignPermissionToRole(roleId: string, permissionId: string): Promise<void> {\n if (!this.db.role_permissions.find(rp => rp.roleId === roleId && rp.permissionId === permissionId)) {\n this.db.role_permissions.push({ roleId, permissionId })\n this.scheduleWrite()\n }\n }\n\n async revokePermissionFromRole(roleId: string, permissionId: string): Promise<void> {\n this.db.role_permissions = this.db.role_permissions.filter(\n rp => !(rp.roleId === roleId && rp.permissionId === permissionId)\n )\n this.scheduleWrite()\n }\n\n // ── Audit ──────────────────────────────────────────────────────────────────\n\n async createLog(data: CreateAuditLogInput): Promise<void> {\n const log: AuditLog = {\n id: randomUUID(),\n tenantId: data.tenantId,\n action: data.action,\n resourceType: data.resourceType,\n createdAt: new Date().toISOString(),\n ...(data.userId != null && { userId: data.userId }),\n ...(data.resourceId != null && { resourceId: data.resourceId }),\n ...(data.oldData != null && { oldData: data.oldData }),\n ...(data.newData != null && { newData: data.newData }),\n }\n this.db.audit_logs.push(log)\n this.scheduleWrite()\n }\n\n async getLogs(filters: AuditFilters): Promise<AuditLog[]> {\n let rows = this.db.audit_logs.filter(l => l.tenantId === filters.tenantId)\n if (filters.action) rows = rows.filter(l => l.action === filters.action)\n if (filters.resourceType) rows = rows.filter(l => l.resourceType === filters.resourceType)\n if (filters.from) rows = rows.filter(l => l.createdAt >= filters.from!)\n if (filters.to) rows = rows.filter(l => l.createdAt <= filters.to!)\n rows.sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n return page(rows, filters.page ?? 1, filters.limit ?? 50)\n }\n\n async *streamAuditLogs(filters: AuditFilters): AsyncIterable<AuditLog> {\n let rows = this.db.audit_logs.filter(l => l.tenantId === filters.tenantId)\n if (filters.action) rows = rows.filter(l => l.action === filters.action)\n if (filters.from) rows = rows.filter(l => l.createdAt >= filters.from!)\n if (filters.to) rows = rows.filter(l => l.createdAt <= filters.to!)\n rows.sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n for (const log of rows) yield log\n }\n\n // ── Stats ──────────────────────────────────────────────────────────────────\n\n async getOverviewStats(tenantId: string): Promise<OverviewStats> {\n const consents = this.db.consents.filter(c => c.tenantId === tenantId)\n const recent = consents.slice(-500)\n let accepted = 0, rejected = 0\n for (const c of recent) {\n const vals = Object.values(c.consentJson)\n const grantedPct = vals.length > 0 ? vals.filter(v => v === 'granted').length / vals.length : 0\n if (grantedPct >= 0.8) accepted++\n else if (grantedPct <= 0.2) rejected++\n }\n const sample = recent.length || 1\n return {\n totalConsents: consents.length,\n gpcDetectedCount: consents.filter(c => c.gpcDetected).length,\n totalVisitors: this.db.visitors.filter(v => v.tenantId === tenantId).length,\n acceptedPct: Math.round((accepted / sample) * 100),\n rejectedPct: Math.round((rejected / sample) * 100),\n }\n }\n\n async getCategoryStats(tenantId: string): Promise<CategoryStats> {\n const stats: CategoryStats = {}\n for (const c of this.db.consents.filter(c => c.tenantId === tenantId).slice(0, 5000)) {\n for (const [key, status] of Object.entries(c.consentJson)) {\n if (!stats[key]) stats[key] = { granted: 0, denied: 0, objected: 0 }\n if (status === 'granted') stats[key]!.granted++\n else if (status === 'denied') stats[key]!.denied++\n else if (status === 'objected') stats[key]!.objected++\n }\n }\n return stats\n }\n\n async getTimeline(tenantId: string, days = 30): Promise<TimelineEntry[]> {\n const cutoff = new Date(Date.now() - days * 86_400_000).toISOString().slice(0, 10)\n const counts = new Map<string, number>()\n for (const c of this.db.consents.filter(c => c.tenantId === tenantId && c.createdAt.slice(0, 10) >= cutoff)) {\n const date = c.createdAt.slice(0, 10)\n counts.set(date, (counts.get(date) ?? 0) + 1)\n }\n return [...counts.entries()]\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([date, count]) => ({ date, count }))\n }\n\n async getCountries(tenantId: string): Promise<CountryStat[]> {\n const consentVisitors = new Set(\n this.db.consents.filter(c => c.tenantId === tenantId).map(c => c.visitorId)\n )\n const counts = new Map<string, number>()\n for (const v of this.db.visitors.filter(v => consentVisitors.has(v.visitorId) && v.country)) {\n const c = v.country!\n counts.set(c, (counts.get(c) ?? 0) + 1)\n }\n return [...counts.entries()]\n .sort(([, a], [, b]) => b - a)\n .slice(0, 50)\n .map(([country, count]) => ({ country, count }))\n }\n\n async getGpcStats(tenantId: string): Promise<GpcStats> {\n const consents = this.db.consents.filter(c => c.tenantId === tenantId)\n const detected = consents.filter(c => c.gpcDetected).length\n const total = consents.length\n return { detected, total, rate: total > 0 ? Math.round((detected / total) * 100) : 0 }\n }\n\n // ── Tenants ────────────────────────────────────────────────────────────────\n\n async getTenants(): Promise<Tenant[]> {\n return [...this.db.tenants].sort((a, b) => a.name.localeCompare(b.name))\n }\n\n async createTenant(data: CreateTenantInput): Promise<Tenant> {\n const now = new Date().toISOString()\n const tenant: Tenant = { id: randomUUID(), name: data.name, slug: data.slug, createdAt: now, updatedAt: now }\n this.db.tenants.push(tenant)\n this.scheduleWrite()\n return tenant\n }\n\n async updateTenant(id: string, data: UpdateTenantInput): Promise<Tenant> {\n const idx = this.db.tenants.findIndex(t => t.id === id)\n if (idx === -1) throw new Error(`Tenant ${id} not found`)\n const now = new Date().toISOString()\n const updated: Tenant = {\n ...this.db.tenants[idx]!,\n ...(data.name != null && { name: data.name }),\n ...(data.slug != null && { slug: data.slug }),\n updatedAt: now,\n }\n this.db.tenants[idx] = updated\n this.scheduleWrite()\n return updated\n }\n\n async deleteTenant(id: string): Promise<void> {\n this.db.tenants = this.db.tenants.filter(t => t.id !== id)\n this.scheduleWrite()\n }\n\n async purgeExpiredConsents(olderThanDays: number): Promise<number> {\n const cutoff = new Date(Date.now() - olderThanDays * 86_400_000).toISOString()\n const toDelete = new Set(\n this.db.consents.filter(c => c.createdAt < cutoff).map(c => c.visitorId)\n )\n if (toDelete.size === 0) return 0\n this.db.consent_history = this.db.consent_history.filter(h => !toDelete.has(h.visitorId))\n this.db.consents = this.db.consents.filter(c => !toDelete.has(c.visitorId))\n this.scheduleWrite()\n return toDelete.size\n }\n\n // ── API Keys ───────────────────────────────────────────────────────────────\n\n async createApiKey(data: CreateApiKeyInput): Promise<ApiKey> {\n const key: ApiKey = {\n id: randomUUID(),\n tenantId: data.tenantId,\n keyHash: data.keyHash,\n name: data.name,\n isActive: true,\n createdAt: new Date().toISOString(),\n }\n this.db.api_keys.push(key)\n this.scheduleWrite()\n return key\n }\n\n async getApiKeyByHash(keyHash: string): Promise<ApiKey | null> {\n return this.db.api_keys.find(k => k.keyHash === keyHash && k.isActive) ?? null\n }\n\n async revokeApiKey(id: string): Promise<void> {\n const key = this.db.api_keys.find(k => k.id === id)\n if (key) { key.isActive = false; this.scheduleWrite() }\n }\n\n async getApiKeys(tenantId: string): Promise<ApiKey[]> {\n return this.db.api_keys\n .filter(k => k.tenantId === tenantId)\n .sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n }\n\n // ── Cookie Templates ───────────────────────────────────────────────────────\n\n async createCookieTemplate(data: CreateCookieTemplateInput): Promise<ServerCookieTemplate> {\n const now = new Date().toISOString()\n const tpl: ServerCookieTemplate = {\n id: randomUUID(), tenantId: data.tenantId, name: data.name,\n cookies: data.cookies, createdAt: now, updatedAt: now,\n }\n this.db.cookie_templates.push(tpl)\n this.scheduleWrite()\n return tpl\n }\n\n async updateCookieTemplate(id: string, data: UpdateCookieTemplateInput): Promise<ServerCookieTemplate> {\n const idx = this.db.cookie_templates.findIndex(t => t.id === id)\n if (idx === -1) throw new Error('Cookie template not found')\n const now = new Date().toISOString()\n const updated: ServerCookieTemplate = {\n ...this.db.cookie_templates[idx]!,\n ...(data.name !== undefined && { name: data.name }),\n ...(data.cookies !== undefined && { cookies: data.cookies }),\n updatedAt: now,\n }\n this.db.cookie_templates[idx] = updated\n this.scheduleWrite()\n return updated\n }\n\n async deleteCookieTemplate(id: string): Promise<void> {\n this.db.cookie_templates = this.db.cookie_templates.filter(t => t.id !== id)\n this.scheduleWrite()\n }\n\n async getCookieTemplate(id: string): Promise<ServerCookieTemplate | null> {\n return this.db.cookie_templates.find(t => t.id === id) ?? null\n }\n\n async getCookieTemplates(tenantId: string): Promise<ServerCookieTemplate[]> {\n return this.db.cookie_templates\n .filter(t => t.tenantId === tenantId)\n .sort((a, b) => a.name.localeCompare(b.name))\n }\n\n async copyCookieTemplate(id: string, newName: string): Promise<ServerCookieTemplate> {\n const src = await this.getCookieTemplate(id)\n if (!src) throw new Error('Cookie template not found')\n return this.createCookieTemplate({ tenantId: src.tenantId, name: newName, cookies: src.cookies })\n }\n\n // ── UI Templates ───────────────────────────────────────────────────────────\n\n async createUITemplate(data: CreateUITemplateInput): Promise<ServerUITemplate> {\n const now = new Date().toISOString()\n const { tenantId, name, ...settings } = data\n const tpl = { id: randomUUID(), tenantId, name, ...settings, createdAt: now, updatedAt: now } as ServerUITemplate\n this.db.ui_templates.push(tpl)\n this.scheduleWrite()\n return tpl\n }\n\n async updateUITemplate(id: string, data: UpdateUITemplateInput): Promise<ServerUITemplate> {\n const idx = this.db.ui_templates.findIndex(t => t.id === id)\n if (idx === -1) throw new Error('UI template not found')\n const { name: _name, ...settings } = data\n const now = new Date().toISOString()\n const updated = {\n ...this.db.ui_templates[idx]!,\n ...(data.name !== undefined && { name: data.name }),\n ...settings,\n updatedAt: now,\n } as ServerUITemplate\n this.db.ui_templates[idx] = updated\n this.scheduleWrite()\n return updated\n }\n\n async deleteUITemplate(id: string): Promise<void> {\n this.db.ui_templates = this.db.ui_templates.filter(t => t.id !== id)\n this.scheduleWrite()\n }\n\n async getUITemplate(id: string): Promise<ServerUITemplate | null> {\n return this.db.ui_templates.find(t => t.id === id) ?? null\n }\n\n async getUITemplates(tenantId: string): Promise<ServerUITemplate[]> {\n return this.db.ui_templates\n .filter(t => t.tenantId === tenantId)\n .sort((a, b) => a.name.localeCompare(b.name))\n }\n\n async copyUITemplate(id: string, newName: string): Promise<ServerUITemplate> {\n const src = await this.getUITemplate(id)\n if (!src) throw new Error('UI template not found')\n const { tenantId, mainBanner, gpcBanner, preferenceModal } = src as ServerUITemplate & {\n mainBanner?: unknown; gpcBanner?: unknown; preferenceModal?: unknown\n }\n return this.createUITemplate({\n tenantId, name: newName,\n ...(mainBanner !== undefined && { mainBanner }),\n ...(gpcBanner !== undefined && { gpcBanner }),\n ...(preferenceModal !== undefined && { preferenceModal }),\n } as CreateUITemplateInput)\n }\n\n // ── Profile summaries ──────────────────────────────────────────────────────\n\n private profileToSummary(p: Profile): ProfileSummary {\n const json = p.profileJson as ProfileConfig & { complianceGroup?: string; isActive?: boolean; cookieTemplateId?: string; uiTemplateId?: string }\n const ct = json.cookieTemplateId ? this.db.cookie_templates.find(t => t.id === json.cookieTemplateId) : null\n const ut = json.uiTemplateId ? this.db.ui_templates.find(t => t.id === json.uiTemplateId) : null\n return {\n id: p.id,\n name: p.name,\n defaultLocale: p.defaultLocale,\n complianceGroup: (json.complianceGroup ?? null) as ComplianceGroupId | null,\n version: p.version,\n isActive: json.isActive ?? false,\n cookieTemplateName: ct?.name ?? null,\n uiTemplateName: ut?.name ?? null,\n createdAt: p.createdAt,\n updatedAt: p.updatedAt,\n }\n }\n\n async listProfilesSummary(tenantId: string): Promise<ProfileSummary[]> {\n return this.db.profiles\n .filter(p => p.tenantId === tenantId)\n .sort((a, b) => a.createdAt.localeCompare(b.createdAt))\n .map(p => this.profileToSummary(p))\n }\n\n async findProfilesUsingCookieTemplate(templateId: string): Promise<ProfileSummary[]> {\n return this.db.profiles\n .filter(p => {\n const json = p.profileJson as { cookieTemplateId?: string }\n return json.cookieTemplateId === templateId\n })\n .sort((a, b) => a.name.localeCompare(b.name))\n .map(p => this.profileToSummary(p))\n }\n\n async findProfilesUsingUITemplate(templateId: string): Promise<ProfileSummary[]> {\n return this.db.profiles\n .filter(p => {\n const json = p.profileJson as { uiTemplateId?: string }\n return json.uiTemplateId === templateId\n })\n .sort((a, b) => a.name.localeCompare(b.name))\n .map(p => this.profileToSummary(p))\n }\n\n // ── Analytics ──────────────────────────────────────────────────────────────\n\n async getOptInStats(tenantId: string, filters: OptInFilters): Promise<OptInStats> {\n let records = this.db.consents.filter(c => c.tenantId === tenantId)\n if (filters.profileId) records = records.filter(c => c.profileId === filters.profileId)\n if (filters.from) records = records.filter(c => c.createdAt >= filters.from!)\n if (filters.to) records = records.filter(c => c.createdAt <= filters.to!)\n if (filters.locale) records = records.filter(c => c.locale === filters.locale)\n\n let total = 0, granted = 0, denied = 0, managed = 0\n const byLocale: Record<string, { total: number; granted: number; denied: number; managed: number }> = {}\n const dateMap = new Map<string, { total: number; granted: number; denied: number; managed: number }>()\n\n for (const r of records) {\n const statuses = Object.values(r.consentJson as Record<string, string>)\n const grantedPct = statuses.length > 0 ? statuses.filter(s => s === 'granted').length / statuses.length : 0\n const deniedPct = statuses.length > 0 ? statuses.filter(s => s === 'denied').length / statuses.length : 0\n total++\n const loc = r.locale\n if (!byLocale[loc]) byLocale[loc] = { total: 0, granted: 0, denied: 0, managed: 0 }\n byLocale[loc]!.total++\n\n const date = r.createdAt.slice(0, 10)\n const entry = dateMap.get(date) ?? { total: 0, granted: 0, denied: 0, managed: 0 }\n entry.total++\n\n if (grantedPct >= 0.9) { granted++; byLocale[loc]!.granted++; entry.granted++ }\n else if (deniedPct >= 0.9) { denied++; byLocale[loc]!.denied++; entry.denied++ }\n else { managed++; byLocale[loc]!.managed++; entry.managed++ }\n dateMap.set(date, entry)\n }\n\n const byDate = Array.from(dateMap.entries())\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([date, v]) => ({ date, ...v }))\n\n return {\n total, granted, denied, managed,\n grantedPct: total > 0 ? Math.round((granted / total) * 1000) / 10 : 0,\n deniedPct: total > 0 ? Math.round((denied / total) * 1000) / 10 : 0,\n managedPct: total > 0 ? Math.round((managed / total) * 1000) / 10 : 0,\n byLocale,\n byDate,\n }\n }\n}\n","import type {\n StorageAdapter, Profile, CreateProfileInput, UpdateProfileInput,\n} from '@consenti/types'\n\nexport class ProfileRepo {\n constructor(private adapter: StorageAdapter) {}\n\n create(data: CreateProfileInput): Promise<Profile> {\n return this.adapter.createProfile(data)\n }\n\n update(id: string, data: UpdateProfileInput): Promise<Profile> {\n return this.adapter.updateProfile(id, data)\n }\n\n delete(id: string): Promise<void> {\n return this.adapter.deleteProfile(id)\n }\n\n get(id: string): Promise<Profile | null> {\n return this.adapter.getProfile(id)\n }\n\n list(tenantId: string): Promise<Profile[]> {\n return this.adapter.getProfiles(tenantId)\n }\n\n findActiveByComplianceGroup(tenantId: string, complianceGroup: string): Promise<Profile | null> {\n return this.adapter.findActiveProfileByComplianceGroup(tenantId, complianceGroup)\n }\n}\n","import type {\n StorageAdapter, ConsentDbRecord, CreateConsentInput, UpdateConsentInput, ConsentFilters,\n} from '@consenti/types'\n\nexport class ConsentRepo {\n constructor(private adapter: StorageAdapter) {}\n\n create(data: CreateConsentInput): Promise<ConsentDbRecord> {\n return this.adapter.createConsent(data)\n }\n\n update(visitorId: string, data: UpdateConsentInput): Promise<ConsentDbRecord> {\n return this.adapter.updateConsent(visitorId, data)\n }\n\n delete(visitorId: string): Promise<void> {\n return this.adapter.deleteConsent(visitorId)\n }\n\n get(visitorId: string): Promise<ConsentDbRecord | null> {\n return this.adapter.getConsent(visitorId)\n }\n\n list(filters: ConsentFilters): Promise<ConsentDbRecord[]> {\n return this.adapter.getConsents(filters)\n }\n}\n","import type {\n StorageAdapter, Visitor, CreateVisitorInput, UpdateVisitorInput,\n} from '@consenti/types'\n\nexport class VisitorRepo {\n constructor(private adapter: StorageAdapter) {}\n\n create(data: CreateVisitorInput): Promise<Visitor> {\n return this.adapter.createVisitor(data)\n }\n\n update(visitorId: string, data: UpdateVisitorInput): Promise<Visitor> {\n return this.adapter.updateVisitor(visitorId, data)\n }\n\n delete(visitorId: string): Promise<void> {\n return this.adapter.deleteVisitor(visitorId)\n }\n\n get(visitorId: string): Promise<Visitor | null> {\n return this.adapter.getVisitor(visitorId)\n }\n}\n","import type {\n StorageAdapter, AuditLog, AuditFilters, CreateAuditLogInput,\n} from '@consenti/types'\n\nexport class AuditRepo {\n constructor(private adapter: StorageAdapter) {}\n\n log(data: CreateAuditLogInput): Promise<void> {\n return this.adapter.createLog(data)\n }\n\n list(filters: AuditFilters): Promise<AuditLog[]> {\n return this.adapter.getLogs(filters)\n }\n}\n","import type {\n StorageAdapter,\n AdminUser,\n CreateUserInput,\n UpdateUserInput,\n Role,\n} from '@consenti/types'\n\nexport class UserRepo {\n constructor(private adapter: StorageAdapter) {}\n\n getById(id: string): Promise<AdminUser | null> { return this.adapter.getUserById(id) }\n getByEmail(email: string): Promise<AdminUser | null> { return this.adapter.getUserByEmail(email) }\n list(tenantId: string): Promise<AdminUser[]> { return this.adapter.getUsers(tenantId) }\n create(data: CreateUserInput): Promise<AdminUser> { return this.adapter.createUser(data) }\n update(id: string, data: UpdateUserInput): Promise<AdminUser> { return this.adapter.updateUser(id, data) }\n delete(id: string): Promise<void> { return this.adapter.deleteUser(id) }\n getRoles(userId: string, tenantId?: string): Promise<Role[]> { return this.adapter.getUserRoles(userId, tenantId) }\n assignRole(userId: string, roleId: string, tenantId?: string): Promise<void> { return this.adapter.assignRole(userId, roleId, tenantId) }\n revokeRole(userId: string, roleId: string, tenantId?: string): Promise<void> { return this.adapter.revokeRole(userId, roleId, tenantId) }\n}\n","import type { Profile, LocaleTranslations, ProfileTranslations } from '@consenti/types'\n\nfunction mergeTranslations(base: LocaleTranslations, override: Partial<LocaleTranslations>): LocaleTranslations {\n return {\n mainBanner: { ...base.mainBanner, ...override.mainBanner },\n preferenceModal: {\n ...base.preferenceModal,\n ...override.preferenceModal,\n buttons: override.preferenceModal?.buttons ?? base.preferenceModal.buttons,\n categories: override.preferenceModal?.categories ?? base.preferenceModal.categories,\n },\n ...(override.gpcBanner != null || base.gpcBanner != null\n ? { gpcBanner: { ...(base.gpcBanner ?? base.mainBanner), ...override.gpcBanner } }\n : {}),\n }\n}\n\nexport function resolveLocale(\n translations: ProfileTranslations,\n requested: string,\n defaultLocale: string,\n): LocaleTranslations {\n const base = translations[defaultLocale]\n if (!base) throw new Error(`Default locale '${defaultLocale}' not found in translations`)\n\n if (requested === defaultLocale) return base\n\n const exact = translations[requested]\n if (exact) return mergeTranslations(base, exact)\n\n const lang = requested.split('-')[0] ?? ''\n const langMatch = lang ? translations[lang] : undefined\n if (langMatch) return mergeTranslations(base, langMatch)\n\n return base\n}\n\nexport function resolveProfile(\n profile: Profile,\n locale: string,\n): { profile: Profile; resolved: LocaleTranslations } {\n const translations = profile.profileJson.translations ?? {}\n const resolved = resolveLocale(translations, locale, profile.defaultLocale)\n return { profile, resolved }\n}\n\nexport function bumpVersion(profile: Profile): number {\n return profile.version + 1\n}\n","import type { Profile, CreateProfileInput, UpdateProfileInput, PublicProfileResponse, ProfileSummary, ProfileVersionEntry, StorageAdapter, LocaleTextContent, ServerUITemplate, LocaleTranslations, Cookie, S3ApiConfig } from '@consenti/types'\nimport { resolveLocale } from '../core/profile-engine'\nimport type { ProfileRepo } from '../repositories/profile.repo'\nimport type { AuditRepo } from '../repositories/audit.repo'\nimport type { EventEmitter } from 'node:events'\nimport type { LocaleJsonCacheService } from './locale-json-cache.service'\nimport { readdirSync, readFileSync, existsSync, statSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { runProfileJsonWrite } from '../workers/profile-json-worker-launcher.js'\nimport type { WorkerMessage } from '../workers/profile-json-worker-core.js'\n\nfunction buildTranslations(template: ServerUITemplate, localeContents: Record<string, LocaleTextContent>): Record<string, LocaleTranslations> {\n const result: Record<string, LocaleTranslations> = {}\n for (const [locale, content] of Object.entries(localeContents)) {\n result[locale] = {\n mainBanner: {\n position: template.mainBanner.position,\n ...(template.mainBanner.overlayOpacity !== undefined ? { overlayOpacity: template.mainBanner.overlayOpacity } : {}),\n ...(template.mainBanner.showClose !== undefined ? { showClose: template.mainBanner.showClose } : {}),\n ...(template.mainBanner.showLocaleSwitcher !== undefined ? { showLocaleSwitcher: template.mainBanner.showLocaleSwitcher } : {}),\n ...(template.mainBanner.headingTag !== undefined ? { headingTag: template.mainBanner.headingTag } : {}),\n ...(content.mainBanner.heading !== undefined ? { heading: content.mainBanner.heading } : {}),\n htmlText: content.mainBanner.htmlText,\n buttons: template.mainBanner.buttons.map((btn, i) => ({\n text: content.mainBanner.buttonLabels?.[i] ?? btn.text,\n style: btn.style,\n action: btn.action,\n ...(btn.url !== undefined ? { url: btn.url } : {}),\n ...(btn.type !== undefined ? { type: btn.type } : {}),\n ...(btn.cookies !== undefined ? { cookies: btn.cookies } : {}),\n })),\n },\n gpcBanner: {\n position: template.gpcBanner.position,\n ...(template.gpcBanner.overlayOpacity !== undefined ? { overlayOpacity: template.gpcBanner.overlayOpacity } : {}),\n ...(template.gpcBanner.showClose !== undefined ? { showClose: template.gpcBanner.showClose } : {}),\n ...(template.gpcBanner.showLocaleSwitcher !== undefined ? { showLocaleSwitcher: template.gpcBanner.showLocaleSwitcher } : {}),\n ...(template.gpcBanner.headingTag !== undefined ? { headingTag: template.gpcBanner.headingTag } : {}),\n ...(content.gpcBanner.heading !== undefined ? { heading: content.gpcBanner.heading } : {}),\n htmlText: content.gpcBanner.htmlText,\n buttons: template.gpcBanner.buttons.map((btn, i) => ({\n text: content.gpcBanner.buttonLabels?.[i] ?? btn.text,\n style: btn.style,\n action: btn.action,\n ...(btn.url !== undefined ? { url: btn.url } : {}),\n ...(btn.type !== undefined ? { type: btn.type } : {}),\n ...(btn.cookies !== undefined ? { cookies: btn.cookies } : {}),\n })),\n },\n preferenceModal: {\n ...(template.preferenceModal.position !== undefined ? { position: template.preferenceModal.position } : {}),\n ...(template.preferenceModal.overlayOpacity !== undefined ? { overlayOpacity: template.preferenceModal.overlayOpacity } : {}),\n ...(template.preferenceModal.showClose !== undefined ? { showClose: template.preferenceModal.showClose } : {}),\n ...(template.preferenceModal.showLocaleSwitcher !== undefined ? { showLocaleSwitcher: template.preferenceModal.showLocaleSwitcher } : {}),\n ...(template.preferenceModal.persistent !== undefined ? { persistent: template.preferenceModal.persistent } : {}),\n ...(template.preferenceModal.headingTag !== undefined ? { headingTag: template.preferenceModal.headingTag } : {}),\n ...(template.preferenceModal.mobileFullScreenBreakpoint !== undefined ? { mobileFullScreenBreakpoint: template.preferenceModal.mobileFullScreenBreakpoint } : {}),\n heading: content.preferenceModal.heading ?? '',\n ...(content.preferenceModal.subheading !== undefined ? { subheading: content.preferenceModal.subheading } : {}),\n htmlText: content.preferenceModal.htmlText ?? '',\n buttons: template.preferenceModal.buttons.map((btn, i) => ({\n text: content.preferenceModal.buttonLabels?.[i] ?? btn.text,\n style: btn.style,\n action: btn.action,\n ...(btn.url !== undefined ? { url: btn.url } : {}),\n ...(btn.type !== undefined ? { type: btn.type } : {}),\n ...(btn.cookies !== undefined ? { cookies: btn.cookies } : {}),\n })),\n categories: template.preferenceModal.categories.map(cat => {\n const c = content.preferenceModal.categories.find(c => c.id === cat.id)\n return {\n id: cat.id,\n heading: c?.heading ?? cat.id,\n ...(cat.headingTag !== undefined ? { headingTag: cat.headingTag } : {}),\n htmlText: c?.htmlText ?? '',\n ...(cat.mandatory !== undefined ? { mandatory: cat.mandatory } : {}),\n ...(cat.type !== undefined ? { type: cat.type } : {}),\n ...(cat.legitimateInterest?.enabled ? { legitimateInterest: { enabled: true as const } } : {}),\n cookies: cat.cookies,\n }\n }),\n },\n }\n }\n return result\n}\n\nfunction normaliseCookieLegalBasis(cookie: Cookie): Cookie {\n if (cookie.legalBasis) return cookie\n if (cookie.mandatory) return { ...cookie, legalBasis: 'mandatory' }\n if (cookie.type) return { ...cookie, legalBasis: cookie.type }\n return cookie\n}\n\nexport class ProfileService {\n constructor(\n private profiles: ProfileRepo,\n private audit: AuditRepo,\n private tenantId: string = 'default',\n private storage?: StorageAdapter,\n private eventBus?: EventEmitter,\n private localeCache?: LocaleJsonCacheService,\n private profilesDir?: string,\n private handleCache?: (paths: string[], version: number, isPurge: boolean) => void,\n private s3Config?: S3ApiConfig,\n ) { }\n\n private profileDir(profileId: string): string {\n return join(this.profilesDir ?? '', this.tenantId, profileId)\n }\n\n private complianceGroupDir(complianceGroup: string): string {\n return join(this.profilesDir ?? '', this.tenantId, complianceGroup)\n }\n\n private profileFilePaths(complianceGroup: string, locales: string[]): string[] {\n const dir = this.complianceGroupDir(complianceGroup)\n return locales.map(l => join(dir, `${l}.json`)).concat(join(dir, 'default.json'))\n }\n\n async create(input: Omit<CreateProfileInput, 'tenantId'>): Promise<Profile> {\n const profile = await this.profiles.create({ ...input, tenantId: this.tenantId })\n await this.audit.log({\n tenantId: this.tenantId,\n action: 'profile.created',\n resourceType: 'profile',\n resourceId: profile.id,\n newData: profile,\n })\n this.eventBus?.emit('profile.created', profile)\n\n if (this.profilesDir) {\n const resolved = await this.getResolved(profile.id)\n if (resolved) {\n const complianceGroup = (profile.profileJson as { complianceGroup?: string }).complianceGroup ?? ''\n await this.runWrite({ action: 'write', profile: resolved, profileId: profile.id, version: profile.version, complianceGroup })\n const paths = this.profileFilePaths(complianceGroup, resolved.locales)\n this.handleCache?.(paths, profile.version, false)\n this.eventBus?.emit('cache:warm', { paths, version: profile.version })\n }\n }\n return profile\n }\n\n async update(id: string, input: UpdateProfileInput): Promise<Profile> {\n const old = await this.profiles.get(id)\n const profile = await this.profiles.update(id, input)\n this.localeCache?.invalidate(id)\n await this.audit.log({\n tenantId: this.tenantId,\n action: 'profile.updated',\n resourceType: 'profile',\n resourceId: id,\n ...(old != null ? { oldData: old } : {}),\n newData: profile,\n })\n this.eventBus?.emit('profile.updated', { previous: old, current: profile })\n\n if (this.profilesDir) {\n const resolved = await this.getResolved(profile.id)\n if (resolved) {\n const complianceGroup = (profile.profileJson as { complianceGroup?: string }).complianceGroup ?? ''\n const isActive = (profile.profileJson as { isActive?: boolean }).isActive ?? false\n const action: WorkerMessage['action'] = isActive ? 'activate' : 'write'\n await this.runWrite({ action, profile: resolved, profileId: id, version: profile.version, complianceGroup })\n if (isActive) {\n const paths = this.profileFilePaths(complianceGroup, resolved.locales)\n this.handleCache?.(paths, profile.version, true)\n this.eventBus?.emit('cache:purge', { paths, version: profile.version })\n }\n }\n }\n return profile\n }\n\n async delete(id: string): Promise<void> {\n const old = await this.profiles.get(id)\n await this.profiles.delete(id)\n this.localeCache?.invalidate(id)\n await this.audit.log({\n tenantId: this.tenantId,\n action: 'profile.deleted',\n resourceType: 'profile',\n resourceId: id,\n ...(old != null ? { oldData: old } : {}),\n })\n this.eventBus?.emit('profile.deleted', { id, previous: old })\n\n if (this.profilesDir && old) {\n const complianceGroup = (old.profileJson as { complianceGroup?: string }).complianceGroup ?? ''\n const wasActive = (old.profileJson as { isActive?: boolean }).isActive ?? false\n if (wasActive && complianceGroup) {\n const resolved = await this.getResolved(id).catch(() => null)\n const locales = resolved?.locales ?? []\n await this.runWrite({ action: 'deactivate', profile: resolved ?? {} as PublicProfileResponse, profileId: id, version: old.version, complianceGroup })\n const paths = this.profileFilePaths(complianceGroup, locales)\n this.handleCache?.(paths, old.version, true)\n this.eventBus?.emit('cache:purge', { paths, version: old.version })\n }\n }\n }\n\n async activate(id: string): Promise<Profile> {\n const profile = await this.profiles.get(id)\n if (!profile) throw new Error(`Profile ${id} not found`)\n const pj = profile.profileJson as { complianceGroup?: string; isActive?: boolean }\n const updated = await this.profiles.update(id, {\n profileJson: { ...profile.profileJson, isActive: true },\n })\n this.localeCache?.invalidate(id)\n\n if (this.profilesDir && pj.complianceGroup) {\n const resolved = await this.getResolved(id)\n if (resolved) {\n await this.runWrite({ action: 'activate', profile: resolved, profileId: id, version: updated.version, complianceGroup: pj.complianceGroup })\n const paths = this.profileFilePaths(pj.complianceGroup, resolved.locales)\n this.handleCache?.(paths, updated.version, false)\n this.eventBus?.emit('cache:warm', { paths, version: updated.version })\n }\n }\n await this.audit.log({ tenantId: this.tenantId, action: 'profile.activated', resourceType: 'profile', resourceId: id })\n this.eventBus?.emit('profile.activated', updated)\n return updated\n }\n\n async deactivate(id: string): Promise<Profile> {\n const profile = await this.profiles.get(id)\n if (!profile) throw new Error(`Profile ${id} not found`)\n const pj = profile.profileJson as { complianceGroup?: string; isActive?: boolean }\n const updated = await this.profiles.update(id, {\n profileJson: { ...profile.profileJson, isActive: false },\n })\n this.localeCache?.invalidate(id)\n\n if (this.profilesDir && pj.complianceGroup) {\n const resolved = await this.getResolved(id)\n const locales = resolved?.locales ?? []\n await this.runWrite({ action: 'deactivate', profile: resolved ?? {} as PublicProfileResponse, profileId: id, version: profile.version, complianceGroup: pj.complianceGroup })\n const paths = this.profileFilePaths(pj.complianceGroup, locales)\n this.handleCache?.(paths, profile.version, true)\n this.eventBus?.emit('cache:purge', { paths, version: profile.version })\n }\n await this.audit.log({ tenantId: this.tenantId, action: 'profile.deactivated', resourceType: 'profile', resourceId: id })\n this.eventBus?.emit('profile.deactivated', updated)\n return updated\n }\n\n private async runWrite(args: { action: WorkerMessage['action']; profile: PublicProfileResponse; profileId: string; version: number; complianceGroup: string }): Promise<void> {\n if (!this.profilesDir) return\n const msg: WorkerMessage = {\n action: args.action,\n profile: args.profile,\n storagePath: join(this.profilesDir, '..'),\n tenantId: this.tenantId,\n profileId: args.profileId,\n version: args.version,\n complianceGroup: args.complianceGroup,\n ...(this.s3Config?.enabled ? { s3Config: this.s3Config } : {}),\n }\n await runProfileJsonWrite(msg)\n }\n\n async get(id: string, locale?: string): Promise<Profile | null> {\n const profile = await this.profiles.get(id)\n if (!profile) return null\n if (!locale) return profile\n const resolved = resolveLocale(profile.profileJson.translations ?? {}, locale, profile.defaultLocale)\n return {\n ...profile,\n profileJson: {\n ...profile.profileJson,\n translations: { [locale]: resolved },\n },\n }\n }\n\n async getResolved(id: string, locale?: string): Promise<PublicProfileResponse | null> {\n const profile = await this.profiles.get(id)\n if (!profile) return null\n\n const currentLocale = locale ?? profile.defaultLocale\n\n // Fast path: locale JSON cache\n if (this.localeCache) {\n const cached = this.localeCache.read(id, currentLocale)\n if (cached) return cached\n }\n\n const pj = profile.profileJson\n let cookies = pj.cookies ?? []\n let translations = pj.translations ?? {}\n\n if (pj.cookieTemplateId && this.storage) {\n const ct = await this.storage.getCookieTemplate(pj.cookieTemplateId)\n if (ct) cookies = ct.cookies\n }\n\n if (pj.uiTemplateId && pj.localeContents && this.storage) {\n const ut = await this.storage.getUITemplate(pj.uiTemplateId)\n if (ut) translations = buildTranslations(ut, pj.localeContents)\n }\n\n const localeKeys = pj.localeContents ? Object.keys(pj.localeContents) : Object.keys(translations)\n const resolved = resolveLocale(translations, currentLocale, profile.defaultLocale)\n const response: PublicProfileResponse = {\n id: profile.id,\n version: profile.version,\n defaultLocale: profile.defaultLocale,\n currentLocale,\n locales: localeKeys,\n cookies: cookies.map(normaliseCookieLegalBasis),\n mainBanner: resolved.mainBanner,\n preferenceModal: resolved.preferenceModal,\n ...(resolved.gpcBanner != null ? { gpcBanner: resolved.gpcBanner } : {}),\n }\n\n if (this.localeCache) {\n try { this.localeCache.write(id, currentLocale, response) } catch { /* non-fatal */ }\n }\n\n return response\n }\n\n findActiveByComplianceGroup(complianceGroup: string): Promise<Profile | null> {\n return this.profiles.findActiveByComplianceGroup(this.tenantId, complianceGroup)\n }\n\n list(): Promise<Profile[]> {\n return this.profiles.list(this.tenantId)\n }\n\n listSummary(): Promise<ProfileSummary[]> {\n if (!this.storage) return Promise.resolve([])\n return this.storage.listProfilesSummary(this.tenantId)\n }\n\n listVersions(profileId: string): ProfileVersionEntry[] {\n if (!this.profilesDir) return []\n const dir = this.profileDir(profileId)\n if (!existsSync(dir)) return []\n const versions: ProfileVersionEntry[] = []\n try {\n const entries = readdirSync(dir, { withFileTypes: true })\n for (const entry of entries) {\n if (!entry.isDirectory()) continue\n const ver = parseInt(entry.name, 10)\n if (isNaN(ver)) continue\n const vdir = join(dir, entry.name)\n const locales = readdirSync(vdir)\n .filter(f => f.endsWith('.json') && f !== 'default.json')\n .map(f => f.replace('.json', ''))\n let createdAt: string\n try {\n createdAt = statSync(vdir).mtime.toISOString()\n } catch {\n createdAt = new Date().toISOString()\n }\n versions.push({ version: ver, createdAt, locales })\n }\n } catch {\n return []\n }\n return versions.sort((a, b) => b.version - a.version)\n }\n\n getVersionFile(profileId: string, version: number, locale: string): string | null {\n if (!this.profilesDir) return null\n const filePath = join(this.profileDir(profileId), String(version), `${locale}.json`)\n if (!existsSync(filePath)) {\n const defaultPath = join(this.profileDir(profileId), String(version), 'default.json')\n if (!existsSync(defaultPath)) return null\n return readFileSync(defaultPath, 'utf8')\n }\n return readFileSync(filePath, 'utf8')\n }\n}\n","import { Worker } from 'node:worker_threads'\nimport { fileURLToPath } from 'node:url'\nimport { join, dirname } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport { runWorkerAction } from './profile-json-worker-core.js'\nimport type { WorkerMessage } from './profile-json-worker-core.js'\n\ntype WorkerResult =\n | { ok: true; action: WorkerMessage['action'] }\n | { ok: false; action: WorkerMessage['action']; error: string }\n\nconst _dir = dirname(fileURLToPath(import.meta.url))\nconst JS_WORKER = join(_dir, 'profile-json.worker.js')\n// In dev (tsx), only the .ts file exists; skip the worker thread entirely and call the core logic directly.\nconst IS_DEV = !existsSync(JS_WORKER)\n\n/**\n * Writes/activates/deactivates profile JSON files.\n * In dev mode runs inline (no worker thread). In production uses a worker thread.\n * Throws if the operation fails so callers can surface the error to the API client.\n */\nexport async function runProfileJsonWrite(msg: WorkerMessage): Promise<void> {\n if (IS_DEV) {\n await runWorkerAction(msg)\n return\n }\n\n return new Promise<void>((resolve, reject) => {\n const worker = new Worker(JS_WORKER)\n worker.postMessage(msg)\n worker.once('message', (result: WorkerResult) => {\n void worker.terminate()\n if (result.ok) {\n resolve()\n } else {\n reject(new Error(`[profile-worker] ${result.action} failed: ${result.error}`))\n }\n })\n worker.once('error', err => {\n void worker.terminate()\n reject(err)\n })\n })\n}\n","import { writeFileSync, readFileSync, renameSync, mkdirSync, readdirSync, copyFileSync, rmSync, existsSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { PublicProfileResponse, S3ApiConfig } from '@consenti/types'\nimport { s3Put, s3Delete } from '../storage/s3/s3-client.js'\n\nexport interface WorkerMessage {\n action: 'write' | 'activate' | 'deactivate'\n profile: PublicProfileResponse & { translations?: Record<string, unknown> }\n storagePath: string\n tenantId: string\n profileId: string\n version: number\n complianceGroup: string\n s3Config?: S3ApiConfig\n}\n\nfunction profilesRoot(storagePath: string, tenantId: string): string {\n return join(storagePath, 'profiles', tenantId)\n}\n\nfunction versionDir(storagePath: string, tenantId: string, profileId: string, version: number): string {\n return join(profilesRoot(storagePath, tenantId), profileId, String(version))\n}\n\nfunction complianceDir(storagePath: string, tenantId: string, complianceGroup: string): string {\n return join(profilesRoot(storagePath, tenantId), complianceGroup)\n}\n\nfunction s3Key(tenantId: string, segment: string, locale: string): string {\n return `profiles/${tenantId}/${segment}/${locale}.json`\n}\n\nfunction writeJsonFile(filePath: string, content: string): void {\n const tmp = filePath + '.tmp'\n writeFileSync(tmp, content, 'utf8')\n JSON.parse(content)\n renameSync(tmp, filePath)\n}\n\nexport async function writeVersionDir(msg: WorkerMessage): Promise<void> {\n const { storagePath, tenantId, profileId, version, profile, s3Config } = msg\n const dir = versionDir(storagePath, tenantId, profileId, version)\n mkdirSync(dir, { recursive: true })\n\n const locales = profile.locales ?? []\n const defaultLocale = profile.defaultLocale\n const translations = (profile as { translations?: Record<string, unknown> }).translations ?? {}\n\n for (const locale of locales) {\n const content = locale === profile.currentLocale\n ? JSON.stringify(profile, null, 2)\n : JSON.stringify({ ...profile, currentLocale: locale, ...(translations[locale] ?? {}) }, null, 2)\n const filePath = join(dir, `${locale}.json`)\n writeJsonFile(filePath, content)\n\n if (locale === defaultLocale) {\n writeJsonFile(join(dir, 'default.json'), content)\n }\n\n if (s3Config?.enabled) {\n await s3Put(s3Key(tenantId, `${profileId}/${version}`, locale), content, s3Config)\n if (locale === defaultLocale) {\n await s3Put(s3Key(tenantId, `${profileId}/${version}`, 'default'), content, s3Config)\n }\n }\n }\n\n if (!existsSync(join(dir, 'default.json'))) {\n const fallbackLocale = locales.includes(defaultLocale) ? defaultLocale : (locales[0] ?? '')\n if (fallbackLocale) {\n const fallbackPath = join(dir, `${fallbackLocale}.json`)\n if (existsSync(fallbackPath)) {\n copyFileSync(fallbackPath, join(dir, 'default.json'))\n }\n }\n }\n}\n\nexport async function activateComplianceGroup(msg: WorkerMessage): Promise<void> {\n const { storagePath, tenantId, profileId, version, complianceGroup, s3Config } = msg\n const srcDir = versionDir(storagePath, tenantId, profileId, version)\n const destDir = complianceDir(storagePath, tenantId, complianceGroup)\n\n mkdirSync(destDir, { recursive: true })\n\n const files = readdirSync(srcDir).filter(f => f.endsWith('.json'))\n for (const file of files) {\n copyFileSync(join(srcDir, file), join(destDir, file))\n\n if (s3Config?.enabled) {\n const content = readFileSync(join(destDir, file), 'utf8')\n await s3Put(s3Key(tenantId, complianceGroup, file.replace('.json', '')), content, s3Config)\n }\n }\n}\n\nexport async function deactivateComplianceGroup(msg: WorkerMessage): Promise<void> {\n const { storagePath, tenantId, complianceGroup, s3Config, profile } = msg\n const dir = complianceDir(storagePath, tenantId, complianceGroup)\n\n if (existsSync(dir)) {\n if (s3Config?.enabled) {\n const locales = profile.locales ?? []\n for (const locale of locales) {\n await s3Delete(s3Key(tenantId, complianceGroup, locale), s3Config)\n }\n await s3Delete(s3Key(tenantId, complianceGroup, 'default'), s3Config)\n }\n rmSync(dir, { recursive: true, force: true })\n }\n}\n\nexport async function runWorkerAction(msg: WorkerMessage): Promise<void> {\n if (msg.action === 'write') {\n await writeVersionDir(msg)\n } else if (msg.action === 'activate') {\n await writeVersionDir(msg)\n await activateComplianceGroup(msg)\n } else if (msg.action === 'deactivate') {\n await deactivateComplianceGroup(msg)\n }\n}\n","import { createHmac, createHash } from 'node:crypto'\nimport type { S3ApiConfig } from '@consenti/types'\n\ntype S3Config = Pick<S3ApiConfig, 'region' | 'bucketName' | 'accessKeyId' | 'secretAccessKey' | 'sessionToken'>\n\nfunction sha256Hex(data: string | Buffer): string {\n return createHash('sha256').update(data).digest('hex')\n}\n\nfunction hmacSha256(key: Buffer | string, data: string): Buffer {\n return createHmac('sha256', key).update(data).digest()\n}\n\nfunction toAmzDate(d: Date): { amzDate: string; dateStamp: string } {\n const iso = d.toISOString().replace(/[-:]/g, '').slice(0, 15) + 'Z'\n return { amzDate: iso, dateStamp: iso.slice(0, 8) }\n}\n\nfunction getSigningKey(secretKey: string, dateStamp: string, region: string, service: string): Buffer {\n const kDate = hmacSha256(`AWS4${secretKey}`, dateStamp)\n const kRegion = hmacSha256(kDate, region)\n const kService = hmacSha256(kRegion, service)\n return hmacSha256(kService, 'aws4_request')\n}\n\ninterface S3RequestParams {\n method: 'PUT' | 'GET' | 'HEAD' | 'DELETE'\n key: string\n body?: Buffer | string\n contentType?: string\n config: S3Config\n}\n\nfunction buildSignedHeaders(params: S3RequestParams): Record<string, string> {\n const { method, key, body, contentType, config } = params\n const now = new Date()\n const { amzDate, dateStamp } = toAmzDate(now)\n const host = `${config.bucketName}.s3.${config.region}.amazonaws.com`\n\n const payloadHash = body\n ? sha256Hex(Buffer.isBuffer(body) ? body : Buffer.from(body as string, 'utf8'))\n : sha256Hex('')\n\n const signedHeaderMap: Record<string, string> = {\n host,\n 'x-amz-date': amzDate,\n 'x-amz-content-sha256': payloadHash,\n }\n if (config.sessionToken) signedHeaderMap['x-amz-security-token'] = config.sessionToken\n if (contentType && method === 'PUT') signedHeaderMap['content-type'] = contentType\n\n const sortedKeys = Object.keys(signedHeaderMap).sort()\n const canonicalHeaders = sortedKeys.map(k => `${k}:${signedHeaderMap[k]}\\n`).join('')\n const signedHeadersList = sortedKeys.join(';')\n\n const canonicalRequest = [\n method,\n `/${encodeURIComponent(key).replace(/%2F/g, '/')}`,\n '',\n canonicalHeaders,\n signedHeadersList,\n payloadHash,\n ].join('\\n')\n\n const credentialScope = `${dateStamp}/${config.region}/s3/aws4_request`\n const stringToSign = [\n 'AWS4-HMAC-SHA256',\n amzDate,\n credentialScope,\n sha256Hex(canonicalRequest),\n ].join('\\n')\n\n const signingKey = getSigningKey(config.secretAccessKey, dateStamp, config.region, 's3')\n const signature = createHmac('sha256', signingKey).update(stringToSign).digest('hex')\n\n const authorization = [\n `AWS4-HMAC-SHA256 Credential=${config.accessKeyId}/${credentialScope}`,\n `SignedHeaders=${signedHeadersList}`,\n `Signature=${signature}`,\n ].join(', ')\n\n return { ...signedHeaderMap, authorization }\n}\n\nfunction s3Url(key: string, config: S3Config): string {\n const encodedKey = encodeURIComponent(key).replace(/%2F/g, '/')\n return `https://${config.bucketName}.s3.${config.region}.amazonaws.com/${encodedKey}`\n}\n\nexport async function s3Put(key: string, body: Buffer | string, config: S3Config, contentType = 'application/json'): Promise<void> {\n const headers = buildSignedHeaders({ method: 'PUT', key, body, contentType, config })\n const bodyStr = typeof body === 'string' ? body : body.toString('utf8')\n const res = await fetch(s3Url(key, config), {\n method: 'PUT',\n headers: { ...headers, 'content-length': String(Buffer.byteLength(bodyStr, 'utf8')) },\n body: bodyStr,\n })\n if (!res.ok) {\n const text = await res.text().catch(() => '')\n throw new Error(`S3 PUT ${key} failed: ${res.status} ${text}`)\n }\n}\n\nexport async function s3Get(key: string, config: S3Config): Promise<Buffer> {\n const headers = buildSignedHeaders({ method: 'GET', key, config })\n const res = await fetch(s3Url(key, config), { method: 'GET', headers })\n if (!res.ok) {\n const text = await res.text().catch(() => '')\n throw new Error(`S3 GET ${key} failed: ${res.status} ${text}`)\n }\n const buf = await res.arrayBuffer()\n return Buffer.from(buf)\n}\n\nexport async function s3Head(key: string, config: S3Config): Promise<boolean> {\n const headers = buildSignedHeaders({ method: 'HEAD', key, config })\n const res = await fetch(s3Url(key, config), { method: 'HEAD', headers })\n return res.ok\n}\n\nexport async function s3Delete(key: string, config: S3Config): Promise<void> {\n const headers = buildSignedHeaders({ method: 'DELETE', key, config })\n const res = await fetch(s3Url(key, config), { method: 'DELETE', headers })\n if (!res.ok && res.status !== 404) {\n const text = await res.text().catch(() => '')\n throw new Error(`S3 DELETE ${key} failed: ${res.status} ${text}`)\n }\n}\n","export const TIMEZONE_TO_COUNTRY: Readonly<Record<string, string>> = {\n // Europe\n 'Europe/Amsterdam': 'NL', 'Europe/Andorra': 'AD', 'Europe/Athens': 'GR',\n 'Europe/Belgrade': 'RS', 'Europe/Berlin': 'DE', 'Europe/Bratislava': 'SK',\n 'Europe/Brussels': 'BE', 'Europe/Bucharest': 'RO', 'Europe/Budapest': 'HU',\n 'Europe/Busingen': 'DE', 'Europe/Chisinau': 'MD', 'Europe/Copenhagen': 'DK',\n 'Europe/Dublin': 'IE', 'Europe/Gibraltar': 'GI', 'Europe/Guernsey': 'GG',\n 'Europe/Helsinki': 'FI', 'Europe/Isle_of_Man': 'IM','Europe/Istanbul': 'TR',\n 'Europe/Jersey': 'JE', 'Europe/Kaliningrad': 'RU','Europe/Kiev': 'UA',\n 'Europe/Kyiv': 'UA', 'Europe/Lisbon': 'PT', 'Europe/Ljubljana': 'SI',\n 'Europe/London': 'GB', 'Europe/Luxembourg': 'LU', 'Europe/Madrid': 'ES',\n 'Europe/Malta': 'MT', 'Europe/Mariehamn': 'FI', 'Europe/Minsk': 'BY',\n 'Europe/Monaco': 'MC', 'Europe/Moscow': 'RU', 'Europe/Nicosia': 'CY',\n 'Europe/Oslo': 'NO', 'Europe/Paris': 'FR', 'Europe/Podgorica': 'ME',\n 'Europe/Prague': 'CZ', 'Europe/Riga': 'LV', 'Europe/Rome': 'IT',\n 'Europe/Samara': 'RU', 'Europe/San_Marino': 'SM', 'Europe/Sarajevo': 'BA',\n 'Europe/Saratov': 'RU', 'Europe/Simferopol': 'UA', 'Europe/Skopje': 'MK',\n 'Europe/Sofia': 'BG', 'Europe/Stockholm': 'SE', 'Europe/Tallinn': 'EE',\n 'Europe/Tirane': 'AL', 'Europe/Ulyanovsk': 'RU', 'Europe/Uzhgorod': 'UA',\n 'Europe/Vaduz': 'LI', 'Europe/Vatican': 'VA', 'Europe/Vienna': 'AT',\n 'Europe/Vilnius': 'LT', 'Europe/Volgograd': 'RU', 'Europe/Warsaw': 'PL',\n 'Europe/Zagreb': 'HR', 'Europe/Zaporozhye': 'UA', 'Europe/Zurich': 'CH',\n 'Atlantic/Reykjavik': 'IS', 'Atlantic/Faroe': 'FO',\n // Americas — US\n 'America/New_York': 'US', 'America/Chicago': 'US', 'America/Denver': 'US',\n 'America/Los_Angeles': 'US', 'America/Anchorage': 'US', 'America/Adak': 'US',\n 'America/Honolulu': 'US', 'America/Phoenix': 'US', 'America/Detroit': 'US',\n 'America/Indiana/Indianapolis': 'US', 'America/Indiana/Knox': 'US',\n 'America/Indiana/Marengo': 'US', 'America/Indiana/Petersburg': 'US',\n 'America/Indiana/Tell_City': 'US', 'America/Indiana/Vevay': 'US',\n 'America/Indiana/Vincennes': 'US', 'America/Indiana/Winamac': 'US',\n 'America/Kentucky/Louisville': 'US', 'America/Kentucky/Monticello': 'US',\n 'America/North_Dakota/Beulah': 'US', 'America/North_Dakota/Center': 'US',\n 'America/North_Dakota/New_Salem': 'US', 'America/Boise': 'US',\n 'America/Menominee': 'US', 'America/Nome': 'US', 'America/Sitka': 'US',\n 'America/Yakutat': 'US', 'America/Juneau': 'US', 'America/Metlakatla': 'US',\n // Americas — Canada\n 'America/Toronto': 'CA', 'America/Vancouver': 'CA', 'America/Winnipeg': 'CA',\n 'America/Halifax': 'CA', 'America/St_Johns': 'CA', 'America/Edmonton': 'CA',\n 'America/Regina': 'CA', 'America/Whitehorse': 'CA', 'America/Yellowknife': 'CA',\n 'America/Iqaluit': 'CA', 'America/Moncton': 'CA', 'America/Glace_Bay': 'CA',\n 'America/Goose_Bay': 'CA', 'America/Swift_Current': 'CA', 'America/Dawson': 'CA',\n 'America/Cambridge_Bay': 'CA', 'America/Dawson_Creek': 'CA', 'America/Fort_Nelson': 'CA',\n 'America/Creston': 'CA', 'America/Rankin_Inlet': 'CA', 'America/Resolute': 'CA',\n 'America/Pangnirtung': 'CA', 'America/Nipigon': 'CA',\n // Americas — Mexico\n 'America/Mexico_City': 'MX', 'America/Cancun': 'MX', 'America/Monterrey': 'MX',\n 'America/Merida': 'MX', 'America/Chihuahua': 'MX', 'America/Hermosillo': 'MX',\n 'America/Mazatlan': 'MX', 'America/Ojinaga': 'MX', 'America/Bahia_Banderas': 'MX',\n 'America/Matamoros': 'MX', 'America/Tijuana': 'MX',\n // Americas — South America\n 'America/Sao_Paulo': 'BR', 'America/Manaus': 'BR', 'America/Belem': 'BR',\n 'America/Fortaleza': 'BR', 'America/Recife': 'BR', 'America/Maceio': 'BR',\n 'America/Bahia': 'BR', 'America/Porto_Velho': 'BR', 'America/Boa_Vista': 'BR',\n 'America/Campo_Grande': 'BR', 'America/Cuiaba': 'BR', 'America/Santarem': 'BR',\n 'America/Rio_Branco': 'BR', 'America/Eirunepe': 'BR', 'America/Noronha': 'BR',\n 'America/Argentina/Buenos_Aires': 'AR', 'America/Argentina/Cordoba': 'AR',\n 'America/Argentina/Salta': 'AR', 'America/Argentina/Jujuy': 'AR',\n 'America/Argentina/Tucuman': 'AR', 'America/Argentina/Catamarca': 'AR',\n 'America/Argentina/La_Rioja': 'AR', 'America/Argentina/San_Juan': 'AR',\n 'America/Argentina/Mendoza': 'AR', 'America/Argentina/San_Luis': 'AR',\n 'America/Argentina/Rio_Gallegos': 'AR', 'America/Argentina/Ushuaia': 'AR',\n 'America/Bogota': 'CO', 'America/Lima': 'PE', 'America/Santiago': 'CL',\n 'America/Caracas': 'VE', 'America/La_Paz': 'BO', 'America/Asuncion': 'PY',\n 'America/Montevideo': 'UY', 'America/Guayaquil': 'EC', 'America/Guyana': 'GY',\n 'America/Paramaribo': 'SR', 'America/Cayenne': 'GF',\n // Americas — Central America & Caribbean\n 'America/Panama': 'PA', 'America/Costa_Rica': 'CR', 'America/Guatemala': 'GT',\n 'America/El_Salvador': 'SV', 'America/Tegucigalpa': 'HN', 'America/Managua': 'NI',\n 'America/Belize': 'BZ', 'America/Havana': 'CU', 'America/Jamaica': 'JM',\n 'America/Nassau': 'BS', 'America/Port_of_Spain': 'TT', 'America/Santo_Domingo': 'DO',\n 'America/Port-au-Prince': 'HT', 'America/Barbados': 'BB', 'America/Martinique': 'MQ',\n 'America/Guadeloupe': 'GP', 'America/Puerto_Rico': 'PR', 'America/St_Kitts': 'KN',\n // Asia — South Asia\n 'Asia/Kolkata': 'IN', 'Asia/Calcutta': 'IN', 'Asia/Karachi': 'PK',\n 'Asia/Dhaka': 'BD', 'Asia/Colombo': 'LK', 'Asia/Kathmandu': 'NP',\n 'Asia/Kabul': 'AF',\n // Asia — East Asia\n 'Asia/Tokyo': 'JP', 'Asia/Seoul': 'KR', 'Asia/Shanghai': 'CN',\n 'Asia/Hong_Kong': 'HK', 'Asia/Macau': 'MO', 'Asia/Taipei': 'TW',\n 'Asia/Ulaanbaatar': 'MN', 'Asia/Choibalsan': 'MN', 'Asia/Hovd': 'MN',\n // Asia — Southeast Asia\n 'Asia/Singapore': 'SG', 'Asia/Bangkok': 'TH', 'Asia/Jakarta': 'ID',\n 'Asia/Kuala_Lumpur': 'MY', 'Asia/Manila': 'PH', 'Asia/Ho_Chi_Minh': 'VN',\n 'Asia/Saigon': 'VN', 'Asia/Phnom_Penh': 'KH', 'Asia/Vientiane': 'LA',\n 'Asia/Rangoon': 'MM', 'Asia/Yangon': 'MM', 'Asia/Pontianak': 'ID',\n 'Asia/Makassar': 'ID', 'Asia/Jayapura': 'ID', 'Asia/Kuching': 'MY',\n 'Asia/Brunei': 'BN', 'Asia/Dili': 'TL',\n // Asia — Central Asia & Middle East\n 'Asia/Tashkent': 'UZ', 'Asia/Almaty': 'KZ', 'Asia/Qyzylorda': 'KZ',\n 'Asia/Aqtau': 'KZ', 'Asia/Aqtobe': 'KZ', 'Asia/Atyrau': 'KZ',\n 'Asia/Oral': 'KZ', 'Asia/Ashgabat': 'TM', 'Asia/Dushanbe': 'TJ',\n 'Asia/Bishkek': 'KG', 'Asia/Yekaterinburg': 'RU',\n 'Asia/Tehran': 'IR', 'Asia/Baghdad': 'IQ', 'Asia/Riyadh': 'SA',\n 'Asia/Dubai': 'AE', 'Asia/Kuwait': 'KW', 'Asia/Qatar': 'QA',\n 'Asia/Bahrain': 'BH', 'Asia/Muscat': 'OM', 'Asia/Beirut': 'LB',\n 'Asia/Jerusalem': 'IL', 'Asia/Tel_Aviv': 'IL', 'Asia/Amman': 'JO',\n 'Asia/Damascus': 'SY', 'Asia/Nicosia': 'CY', 'Asia/Famagusta': 'CY',\n 'Asia/Baku': 'AZ', 'Asia/Yerevan': 'AM', 'Asia/Tbilisi': 'GE',\n 'Asia/Samarkand': 'UZ',\n // Africa\n 'Africa/Cairo': 'EG', 'Africa/Casablanca': 'MA', 'Africa/Lagos': 'NG',\n 'Africa/Nairobi': 'KE', 'Africa/Johannesburg': 'ZA', 'Africa/Addis_Ababa': 'ET',\n 'Africa/Algiers': 'DZ', 'Africa/Tunis': 'TN', 'Africa/Tripoli': 'LY',\n 'Africa/Khartoum': 'SD', 'Africa/Accra': 'GH', 'Africa/Dar_es_Salaam': 'TZ',\n 'Africa/Abidjan': 'CI', 'Africa/Bamako': 'ML', 'Africa/Banjul': 'GM',\n 'Africa/Conakry': 'GN', 'Africa/Dakar': 'SN', 'Africa/Freetown': 'SL',\n 'Africa/Lome': 'TG', 'Africa/Monrovia': 'LR', 'Africa/Nouakchott': 'MR',\n 'Africa/Ouagadougou': 'BF', 'Africa/Sao_Tome': 'ST',\n 'Africa/Bissau': 'GW', 'Africa/Bangui': 'CF', 'Africa/Brazzaville': 'CG',\n 'Africa/Douala': 'CM', 'Africa/Kinshasa': 'CD', 'Africa/Libreville': 'GA',\n 'Africa/Luanda': 'AO', 'Africa/Malabo': 'GQ', 'Africa/Ndjamena': 'TD',\n 'Africa/Niamey': 'NE', 'Africa/Porto-Novo': 'BJ',\n 'Africa/Blantyre': 'MW', 'Africa/Bujumbura': 'BI', 'Africa/Gaborone': 'BW',\n 'Africa/Harare': 'ZW', 'Africa/Kampala': 'UG', 'Africa/Kigali': 'RW',\n 'Africa/Lubumbashi': 'CD', 'Africa/Lusaka': 'ZM', 'Africa/Maputo': 'MZ',\n 'Africa/Maseru': 'LS', 'Africa/Mbabane': 'SZ', 'Africa/Mogadishu': 'SO',\n 'Africa/Windhoek': 'NA', 'Africa/Asmara': 'ER', 'Africa/Djibouti': 'DJ',\n 'Africa/El_Aaiun': 'EH', 'Africa/Juba': 'SS', 'Africa/Ceuta': 'ES',\n // Oceania\n 'Australia/Sydney': 'AU', 'Australia/Melbourne': 'AU', 'Australia/Brisbane': 'AU',\n 'Australia/Perth': 'AU', 'Australia/Adelaide': 'AU', 'Australia/Darwin': 'AU',\n 'Australia/Hobart': 'AU', 'Australia/Canberra': 'AU', 'Australia/Broken_Hill': 'AU',\n 'Australia/Lord_Howe': 'AU', 'Australia/Lindeman': 'AU', 'Australia/Eucla': 'AU',\n 'Pacific/Auckland': 'NZ', 'Pacific/Chatham': 'NZ',\n 'Pacific/Fiji': 'FJ', 'Pacific/Port_Moresby': 'PG', 'Pacific/Bougainville': 'PG',\n 'Pacific/Guam': 'GU', 'Pacific/Saipan': 'MP', 'Pacific/Pago_Pago': 'AS',\n 'Pacific/Apia': 'WS', 'Pacific/Tongatapu': 'TO', 'Pacific/Fakaofo': 'TK',\n 'Pacific/Niue': 'NU', 'Pacific/Rarotonga': 'CK', 'Pacific/Tahiti': 'PF',\n 'Pacific/Marquesas': 'PF', 'Pacific/Gambier': 'PF', 'Pacific/Honolulu': 'US',\n 'Pacific/Johnston': 'US', 'Pacific/Midway': 'UM', 'Pacific/Wake': 'UM',\n 'Pacific/Tarawa': 'KI', 'Pacific/Enderbury': 'KI', 'Pacific/Kiritimati': 'KI',\n 'Pacific/Efate': 'VU', 'Pacific/Guadalcanal': 'SB', 'Pacific/Noumea': 'NC',\n 'Pacific/Nauru': 'NR', 'Pacific/Palau': 'PW', 'Pacific/Chuuk': 'FM',\n 'Pacific/Pohnpei': 'FM', 'Pacific/Kosrae': 'FM', 'Pacific/Majuro': 'MH',\n 'Pacific/Kwajalein': 'MH', 'Pacific/Funafuti': 'TV', 'Pacific/Wallis': 'WF',\n // Russia (non-European)\n 'Asia/Novosibirsk': 'RU', 'Asia/Omsk': 'RU', 'Asia/Krasnoyarsk': 'RU',\n 'Asia/Irkutsk': 'RU', 'Asia/Chita': 'RU', 'Asia/Yakutsk': 'RU',\n 'Asia/Khandyga': 'RU', 'Asia/Vladivostok': 'RU', 'Asia/Ust-Nera': 'RU',\n 'Asia/Magadan': 'RU', 'Asia/Sakhalin': 'RU', 'Asia/Srednekolymsk': 'RU',\n 'Asia/Kamchatka': 'RU', 'Asia/Anadyr': 'RU',\n} as const\n","import type { CountryResolverFn, ComplianceConfig, ComplianceMapData, GeoResult } from '@consenti/types'\nimport { EMBEDDED_COMPLIANCE_MAP } from '@consenti/utils'\nimport { TIMEZONE_TO_COUNTRY } from '../data/timezone-country'\n\ntype JurisdictionMap = typeof EMBEDDED_COMPLIANCE_MAP | ComplianceMapData\n\nexport interface GeoContext {\n ip: string\n language: string\n timezone: string\n}\n\nexport interface ResolvedGeo {\n country: string\n region?: string\n regulation?: string\n complianceGroup: string\n locale?: string | null\n}\n\nconst LANG_TO_COUNTRY: Readonly<Record<string, string>> = {\n 'ar': 'SA', 'cs': 'CZ', 'da': 'DK', 'de': 'DE', 'el': 'GR',\n 'fi': 'FI', 'fr': 'FR', 'he': 'IL', 'hi': 'IN', 'hu': 'HU',\n 'id': 'ID', 'it': 'IT', 'ja': 'JP', 'ko': 'KR', 'nl': 'NL',\n 'no': 'NO', 'pl': 'PL', 'pt': 'BR', 'ro': 'RO', 'ru': 'RU',\n 'sv': 'SE', 'th': 'TH', 'tr': 'TR', 'uk': 'UA', 'vi': 'VN', 'zh': 'CN',\n} as const\n\nexport class GeoResolverService {\n private readonly provider: Exclude<ComplianceConfig['geoDataProvider'], undefined>\n\n constructor(\n provider: ComplianceConfig['geoDataProvider'],\n private readonly map: JurisdictionMap,\n ) {\n // 'default' and 'timezone' are both the timezone+language heuristic\n this.provider = provider ?? 'default'\n }\n\n async resolve(ctx: GeoContext): Promise<ResolvedGeo> {\n let country = ''\n let region: string | undefined\n let regulation: string | undefined\n let locale: string | null = null\n\n if (typeof this.provider === 'function') {\n const result: GeoResult = await (this.provider as CountryResolverFn)(ctx)\n country = result.country ?? ''\n region = result.region ?? undefined\n locale = result.locale\n } else {\n switch (this.provider) {\n case 'default':\n case 'timezone':\n ;({ country } = resolveFromTimezone(ctx.timezone))\n if (!country) {\n ;({ country, region } = resolveFromLanguage(ctx.language))\n }\n break\n case 'language':\n ;({ country, region } = resolveFromLanguage(ctx.language))\n break\n case 'geoip':\n ;({ country, region } = await resolveFromGeoIPLite(ctx.ip))\n break\n case 'hosted-geoip-lite':\n ;({ country, region } = await resolveFromHosted(ctx.ip))\n break\n case 'maxmind':\n ;({ country, region } = await resolveFromMaxmind(ctx.ip))\n break\n }\n }\n\n const geo: ResolvedGeo = { country, complianceGroup: this.resolveGroup(country, region) }\n if (region !== undefined) geo.region = region\n if (regulation !== undefined) geo.regulation = regulation\n if (locale !== null) geo.locale = locale\n return geo\n }\n\n private resolveGroup(country: string, region?: string): string {\n if (!country) return ''\n const countries = this.map.countries as Record<string, {\n complianceGroup: string\n default: string\n overriddenRegions?: Record<string, { complianceGroup: string }>\n }>\n const entry = countries[country]\n if (!entry) return ''\n if (region !== undefined) {\n // region was resolved — use override if present, else base country group\n return entry.overriddenRegions?.[region]?.complianceGroup ?? entry.complianceGroup\n }\n // region not available — use .default (most strict) so we never under-comply\n return entry.default\n }\n}\n\n// ─── Strategy implementations ─────────────────────────────────────────────────\n\nfunction resolveFromLanguage(language: string): { country: string; region?: string } {\n const first = language.split(',')[0]?.trim().split(';')[0]?.trim() ?? ''\n const parts = first.split('-')\n if (parts.length >= 2) {\n const tag = (parts[parts.length - 1] ?? '').toUpperCase()\n if (/^[A-Z]{2}$/.test(tag)) return { country: tag }\n }\n const country = LANG_TO_COUNTRY[(parts[0] ?? '').toLowerCase()] ?? ''\n return { country }\n}\n\nfunction resolveFromTimezone(timezone: string): { country: string } {\n return { country: TIMEZONE_TO_COUNTRY[timezone] ?? '' }\n}\n\nasync function resolveFromGeoIPLite(ip: string): Promise<{ country: string; region?: string }> {\n if (!ip) return { country: '' }\n try {\n // geoip-lite is an optional peer dep — types may not be installed\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n const geoip = await import('geoip-lite') as {\n lookup(ip: string): { country?: string; region?: string } | null\n }\n const r = geoip.lookup(ip)\n const result: { country: string; region?: string } = { country: r?.country ?? '' }\n const reg = r?.region\n if (reg) result.region = reg\n return result\n } catch {\n console.warn('[Consenti] geoip-lite not installed — country detection skipped. Run: npm install geoip-lite')\n return { country: '' }\n }\n}\n\n// 'maxmind' — requires the `maxmind` npm package and a local GeoLite2-City.mmdb database.\n// See HOW_TO_MAXMIND.md for setup instructions.\nasync function resolveFromMaxmind(ip: string): Promise<{ country: string; region?: string }> {\n if (!ip) return { country: '' }\n try {\n // maxmind is an optional peer dep — dynamically imported to avoid hard dependency\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n const maxmind = await import('maxmind') as {\n open<T>(path: string): Promise<{ get(ip: string): T | null }>\n }\n const dbPath = process.env['MAXMIND_DB_PATH'] ?? './GeoLite2-City.mmdb'\n const reader = await maxmind.open<{\n country?: { iso_code?: string }\n subdivisions?: Array<{ iso_code?: string }>\n }>(dbPath)\n const r = reader.get(ip)\n const country = r?.country?.iso_code ?? ''\n const region = r?.subdivisions?.[0]?.iso_code\n const result: { country: string; region?: string } = { country }\n if (region) result.region = region\n return result\n } catch {\n console.warn('[Consenti] maxmind not available — country detection skipped. See HOW_TO_MAXMIND.md')\n return { country: '' }\n }\n}\n\n// 'hosted-geoip-lite' built-in: calls ipinfo.io with node:https (zero external dep).\n// For a custom token or endpoint, pass a CountryResolverFn closure instead.\nasync function resolveFromHosted(ip: string): Promise<{ country: string; region?: string }> {\n if (!ip) return { country: '' }\n return new Promise((resolve) => {\n import('node:https').then(({ default: https }) => {\n const url = `https://ipinfo.io/${encodeURIComponent(ip)}/json`\n const req = https.get(url, { timeout: 3000 }, (res) => {\n const chunks: Buffer[] = []\n res.on('data', (c: Buffer) => chunks.push(c))\n res.on('end', () => {\n try {\n const body = JSON.parse(Buffer.concat(chunks).toString()) as {\n country?: string\n region?: string\n }\n const result: { country: string; region?: string } = { country: body.country ?? '' }\n if (body.region) result.region = body.region\n resolve(result)\n } catch {\n resolve({ country: '' })\n }\n })\n })\n req.on('error', () => resolve({ country: '' }))\n req.on('timeout', () => { req.destroy(); resolve({ country: '' }) })\n }).catch(() => resolve({ country: '' }))\n })\n}\n","import { existsSync, readFileSync, readdirSync, unlinkSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { PublicProfileResponse } from '@consenti/types'\nimport { safeJsonWrite } from '../utils/safe-json-write'\n\nfunction isPublicProfileResponse(v: unknown): v is PublicProfileResponse {\n return (\n typeof v === 'object' &&\n v !== null &&\n typeof (v as Record<string, unknown>)['id'] === 'string' &&\n typeof (v as Record<string, unknown>)['version'] === 'number'\n )\n}\n\nexport class LocaleJsonCacheService {\n constructor(private readonly dir: string) {}\n\n read(profileId: string, locale: string): PublicProfileResponse | null {\n const path = this.path(profileId, locale)\n if (!existsSync(path)) return null\n try {\n const parsed = JSON.parse(readFileSync(path, 'utf8')) as unknown\n return isPublicProfileResponse(parsed) ? parsed : null\n } catch {\n return null\n }\n }\n\n write(profileId: string, locale: string, response: PublicProfileResponse): void {\n safeJsonWrite(this.path(profileId, locale), response, isPublicProfileResponse)\n }\n\n rebuild(profileId: string, responses: Map<string, PublicProfileResponse>): void {\n for (const [locale, response] of responses) {\n try {\n this.write(profileId, locale, response)\n } catch (err) {\n console.warn(`[Consenti] locale cache rebuild failed for ${profileId}/${locale}:`, err)\n }\n }\n }\n\n invalidate(profileId: string): void {\n try {\n const prefix = `${profileId}_`\n for (const file of readdirSync(this.dir)) {\n if (file.startsWith(prefix) && file.endsWith('.json')) {\n try { unlinkSync(join(this.dir, file)) } catch { /* ok */ }\n }\n }\n } catch { /* ok if dir doesn't exist */ }\n }\n\n private path(profileId: string, locale: string): string {\n return join(this.dir, `${profileId}_${locale}.json`)\n }\n}\n","import { copyFileSync, writeFileSync, renameSync, unlinkSync, readFileSync, existsSync, mkdirSync } from 'node:fs'\nimport { dirname } from 'node:path'\n\nexport function safeJsonWrite(\n filePath: string,\n data: unknown,\n validateSchema: (parsed: unknown) => boolean,\n): void {\n const bak = filePath + '.bak'\n const tmp = filePath + '.tmp'\n mkdirSync(dirname(filePath), { recursive: true })\n const had = existsSync(filePath)\n if (had) copyFileSync(filePath, bak)\n try {\n writeFileSync(tmp, JSON.stringify(data, null, 2), 'utf8')\n const parsed = JSON.parse(readFileSync(tmp, 'utf8')) as unknown\n if (!validateSchema(parsed)) throw new Error('Schema validation failed for ' + filePath)\n renameSync(tmp, filePath)\n if (had) { try { unlinkSync(bak) } catch { /* ok */ } }\n } catch (err) {\n if (had) { try { copyFileSync(bak, filePath); unlinkSync(bak) } catch { /* ok */ } }\n try { unlinkSync(tmp) } catch { /* ok */ }\n throw err\n }\n}\n","import type {\n ConsentDbRecord,\n ConsentValue,\n ConsentVerifyResult,\n CreateConsentInput,\n Profile,\n Cookie,\n} from '@consenti/types'\n\nexport interface ConsentValidationResult {\n valid: boolean\n errors: string[]\n}\n\nexport function validateConsentInput(\n data: Pick<CreateConsentInput, 'consentJson'>,\n profile: Profile,\n): ConsentValidationResult {\n const errors: string[] = []\n for (const [cookieId, status] of Object.entries(data.consentJson)) {\n const cookie = (profile.profileJson.cookies ?? []).find(c => c.id === cookieId)\n if (!cookie) continue\n if (cookie.mandatory && status !== 'granted') {\n errors.push(`Cookie \"${cookieId}\" is mandatory and cannot be \"${status}\"`)\n }\n if (status === 'objected' && cookie.type !== 'legitimate_interest') {\n errors.push(`Cookie \"${cookieId}\" is type \"${cookie.type ?? 'consent'}\" — 'objected' is only valid for 'legitimate_interest'`)\n }\n }\n return { valid: errors.length === 0, errors }\n}\n\nexport function buildConsentValue(\n cookies: Profile['profileJson']['cookies'],\n submitted: ConsentValue,\n gpcDetected: boolean,\n regulation?: string,\n): ConsentValue {\n const result: ConsentValue = {}\n for (const cookie of (cookies ?? [])) {\n const id = cookie.id\n if (cookie.mandatory) {\n result[id] = 'granted'\n continue\n }\n // CPRA: GPC triggers Do Not Sell + Do Not Share; sensitive data requires explicit opt-in\n if (regulation === 'cpra') {\n if (cookie.cpraCategory === 'sensitive') {\n // Sensitive data is opt-in even under CPRA — treat like GDPR (deny by default)\n const status = submitted[id]\n result[id] = (status === 'granted' || status === 'denied' || status === 'objected') ? status : 'denied'\n continue\n }\n if (gpcDetected && (cookie.cpraCategory === 'sale' || cookie.cpraCategory === 'sharing')) {\n result[id] = 'denied'\n continue\n }\n }\n // GDPR/CCPA/DPDPA: honor listenGpc flag\n if (gpcDetected && cookie.listenGpc && regulation !== 'dpdpa') {\n result[id] = 'denied'\n continue\n }\n const status = submitted[id]\n if (status === 'granted' || status === 'denied' || status === 'objected') {\n result[id] = status\n } else {\n result[id] = 'denied'\n }\n }\n return result\n}\n\nexport function verifyConsent(\n record: ConsentDbRecord,\n profile: Profile,\n): ConsentVerifyResult {\n const reasons: ConsentVerifyResult['reasons'] = []\n\n if (record.profileVersion < profile.version) {\n reasons.push('profile_version_mismatch')\n }\n\n if (isExpired(record, profile)) {\n reasons.push('consent_expired')\n }\n\n return {\n valid: reasons.length === 0,\n reasons,\n currentProfileVersion: profile.version,\n consentProfileVersion: record.profileVersion,\n }\n}\n\nexport function buildTcfPayload(\n cookies: Cookie[],\n consentValue: ConsentValue,\n): { vendorConsents: number[]; purposeConsents: number[] } {\n const vendorSet = new Set<number>()\n const purposeSet = new Set<number>()\n for (const cookie of cookies) {\n if (consentValue[cookie.id] !== 'granted') continue\n if (cookie.tcfVendorId) vendorSet.add(cookie.tcfVendorId)\n for (const p of cookie.tcfPurposes ?? []) purposeSet.add(p)\n }\n return {\n vendorConsents: [...vendorSet].sort((a, b) => a - b),\n purposeConsents: [...purposeSet].sort((a, b) => a - b),\n }\n}\n\nfunction isExpired(record: ConsentDbRecord, profile: Profile): boolean {\n const cookies = profile.profileJson.cookies ?? []\n const createdMs = new Date(record.createdAt).getTime()\n const now = Date.now()\n\n for (const cookie of cookies) {\n if (!cookie.expiry) continue\n const expiryMs = createdMs + cookie.expiry * 24 * 60 * 60 * 1000\n if (now > expiryMs) return true\n }\n return false\n}\n","// Simplified TC string encoder/decoder.\n// This implementation stores a base64url-encoded JSON payload for basic compatibility.\n// For full IAB TCF v2.2 compliance (binary bitfield encoding), use the iabtcf-core npm package.\n\nexport interface TcStringInput {\n cmpId: number\n cmpVersion: number\n consentScreen: number\n consentLanguage: string\n vendorListVersion: number\n purposeConsents: number[]\n vendorConsents: number[]\n}\n\nexport function encodeTcString(input: TcStringInput): string {\n const payload = {\n v: 2,\n ts: Math.floor(Date.now() / 100),\n cmpId: input.cmpId,\n cmpV: input.cmpVersion,\n cs: input.consentScreen,\n lang: input.consentLanguage.toUpperCase().slice(0, 2),\n vlV: input.vendorListVersion,\n pc: input.purposeConsents,\n vc: input.vendorConsents,\n }\n return Buffer.from(JSON.stringify(payload)).toString('base64url')\n}\n\nexport interface DecodedTcString {\n version: number\n cmpId: number\n consentLanguage: string\n purposeConsents: number[]\n vendorConsents: number[]\n created: number\n}\n\nexport function decodeTcString(tcString: string): DecodedTcString | null {\n try {\n const raw = JSON.parse(Buffer.from(tcString, 'base64url').toString('utf8')) as {\n v: number; cmpId: number; lang: string; pc: number[]; vc: number[]; ts: number\n }\n return {\n version: raw.v,\n cmpId: raw.cmpId,\n consentLanguage: raw.lang,\n purposeConsents: Array.isArray(raw.pc) ? raw.pc : [],\n vendorConsents: Array.isArray(raw.vc) ? raw.vc : [],\n created: raw.ts * 100,\n }\n } catch {\n return null\n }\n}\n","import type {\n ConsentDbRecord, ConsentVerifyResult, CreateConsentInput, UpdateConsentInput,\n ComplianceConfig, TcfConfig,\n} from '@consenti/types'\nimport { buildConsentValue, verifyConsent, validateConsentInput, buildTcfPayload } from '../core/consent-engine'\nimport { encodeTcString } from '../tcf/tc-string'\nimport { getGvl } from '../tcf/gvl-cache'\nimport type { ConsentRepo } from '../repositories/consent.repo'\nimport type { VisitorRepo } from '../repositories/visitor.repo'\nimport type { ProfileRepo } from '../repositories/profile.repo'\nimport type { AuditRepo } from '../repositories/audit.repo'\nimport type { PluginEngine } from '../core/plugin-engine'\nimport type { EventEmitter } from 'node:events'\n\nexport class ConsentService {\n constructor(\n private consents: ConsentRepo,\n private visitors: VisitorRepo,\n private profiles: ProfileRepo,\n private audit: AuditRepo,\n private tenantId: string = 'default',\n private compliance?: ComplianceConfig,\n private pluginEngine?: PluginEngine,\n private eventBus?: EventEmitter,\n private tcfConfig?: TcfConfig,\n ) {}\n\n async create(input: Omit<CreateConsentInput, 'tenantId'>): Promise<ConsentDbRecord> {\n const profile = await this.profiles.get(input.profileId)\n if (!profile) throw new Error(`Profile ${input.profileId} not found`)\n\n const regulation = profile.profileJson.regulation\n const profileCookies = profile.profileJson.cookies ?? []\n // GPC server-side enforcement — skip for DPDPA (no GPC opt-out signal recognised)\n let effectiveConsent = input.consentJson\n if (input.gpcDetected && this.compliance?.gpc !== false && regulation !== 'dpdpa') {\n effectiveConsent = { ...effectiveConsent }\n for (const cookie of profileCookies) {\n if (regulation === 'cpra') {\n // CPRA: deny sale + sharing on GPC; sensitive stays as submitted\n if (cookie.cpraCategory === 'sale' || cookie.cpraCategory === 'sharing') {\n effectiveConsent[cookie.id] = 'denied'\n }\n } else if (cookie.listenGpc) {\n effectiveConsent[cookie.id] = 'denied'\n }\n }\n }\n\n const validation = validateConsentInput({ ...input, consentJson: effectiveConsent }, profile)\n if (!validation.valid) throw new Error(validation.errors.join('; '))\n\n const builtConsent = buildConsentValue(\n profileCookies,\n effectiveConsent,\n input.gpcDetected,\n regulation,\n )\n\n let tcfString: string | undefined\n if (this.tcfConfig?.enabled && profileCookies.some(c => c.tcfVendorId)) {\n const gvl = await getGvl()\n const { vendorConsents, purposeConsents } = buildTcfPayload(profileCookies, builtConsent)\n tcfString = encodeTcString({\n cmpId: this.tcfConfig.cmpId,\n cmpVersion: this.tcfConfig.cmpVersion,\n consentScreen: 1,\n consentLanguage: input.locale?.slice(0, 2) ?? 'en',\n vendorListVersion: gvl?.vendorListVersion ?? 0,\n purposeConsents,\n vendorConsents,\n })\n }\n\n let baseInput: CreateConsentInput = {\n ...input,\n tenantId: this.tenantId,\n consentJson: builtConsent,\n profileVersion: profile.version,\n ...(tcfString ? { tcfString } : {}),\n }\n if (this.pluginEngine) baseInput = await this.pluginEngine.runBeforeConsentSave(baseInput)\n\n const existing = await this.consents.get(input.visitorId)\n let record: ConsentDbRecord\n\n if (existing) {\n const updateData = await (this.pluginEngine\n ? this.pluginEngine.runBeforeConsentUpdate({ consentJson: builtConsent, locale: input.locale, gpcDetected: input.gpcDetected })\n : Promise.resolve({ consentJson: builtConsent, locale: input.locale, gpcDetected: input.gpcDetected }))\n record = await this.consents.update(input.visitorId, updateData)\n } else {\n record = await this.consents.create(baseInput)\n }\n\n await this.audit.log({\n tenantId: this.tenantId,\n action: existing ? 'consent.updated' : 'consent.created',\n resourceType: 'consent',\n resourceId: record.id,\n ...(existing != null ? { oldData: existing } : {}),\n newData: record,\n })\n\n if (existing) {\n this.eventBus?.emit('consent.updated', { previous: existing, current: record })\n await this.pluginEngine?.runAfterConsentUpdate(record)\n } else {\n this.eventBus?.emit('consent.created', record)\n await this.pluginEngine?.runAfterConsentSave(record)\n }\n\n return record\n }\n\n async update(visitorId: string, input: UpdateConsentInput): Promise<ConsentDbRecord> {\n const existing = await this.consents.get(visitorId)\n if (!existing) throw new Error(`Consent for visitor ${visitorId} not found`)\n\n const profile = await this.profiles.get(existing.profileId)\n if (!profile) throw new Error(`Profile ${existing.profileId} not found`)\n\n const regulation = profile.profileJson.regulation\n const profileCookies2 = profile.profileJson.cookies ?? []\n const effectiveGpc = input.gpcDetected ?? existing.gpcDetected\n let effectiveConsent = input.consentJson\n if (effectiveGpc && this.compliance?.gpc !== false && regulation !== 'dpdpa') {\n effectiveConsent = { ...effectiveConsent }\n for (const cookie of profileCookies2) {\n if (regulation === 'cpra') {\n if (cookie.cpraCategory === 'sale' || cookie.cpraCategory === 'sharing') {\n effectiveConsent[cookie.id] = 'denied'\n }\n } else if (cookie.listenGpc) {\n effectiveConsent[cookie.id] = 'denied'\n }\n }\n }\n\n const builtConsent = buildConsentValue(\n profileCookies2,\n effectiveConsent,\n effectiveGpc,\n regulation,\n )\n\n const record = await this.consents.update(visitorId, { ...input, consentJson: builtConsent })\n await this.audit.log({\n tenantId: this.tenantId,\n action: 'consent.updated',\n resourceType: 'consent',\n resourceId: record.id,\n oldData: existing,\n newData: record,\n })\n return record\n }\n\n get(visitorId: string): Promise<ConsentDbRecord | null> {\n return this.consents.get(visitorId)\n }\n\n async verify(visitorId: string): Promise<ConsentVerifyResult> {\n const record = await this.consents.get(visitorId)\n if (!record) return { valid: false, reasons: ['profile_version_mismatch'] }\n\n const profile = await this.profiles.get(record.profileId)\n if (!profile) return { valid: false, reasons: ['profile_version_mismatch'] }\n\n return verifyConsent(record, profile)\n }\n\n async erase(visitorId: string): Promise<void> {\n const existing = await this.consents.get(visitorId)\n await this.consents.delete(visitorId)\n await this.visitors.delete(visitorId)\n await this.audit.log({\n tenantId: this.tenantId,\n action: 'consent.erased',\n resourceType: 'consent',\n resourceId: visitorId,\n ...(existing != null ? { oldData: existing } : {}),\n })\n this.eventBus?.emit('consent.erased', { visitorId })\n }\n}\n","import type { Visitor, CreateVisitorInput } from '@consenti/types'\nimport { hashIp, hashUserAgent } from '../utils/crypto'\nimport type { VisitorRepo } from '../repositories/visitor.repo'\nimport type { EventEmitter } from 'node:events'\n\nexport class VisitorService {\n constructor(\n private visitors: VisitorRepo,\n private tenantId: string = 'default',\n private eventBus?: EventEmitter,\n ) {}\n\n async upsert(data: {\n visitorId: string\n ip?: string\n userAgent?: string\n country?: string\n region?: string\n city?: string\n }): Promise<Visitor> {\n const existing = await this.visitors.get(data.visitorId)\n if (existing) {\n return this.visitors.update(data.visitorId, {\n ...(data.country != null ? { country: data.country } : {}),\n ...(data.region != null ? { region: data.region } : {}),\n ...(data.city != null ? { city: data.city } : {}),\n })\n }\n const input: CreateVisitorInput = {\n tenantId: this.tenantId,\n visitorId: data.visitorId,\n ...(data.country != null ? { country: data.country } : {}),\n ...(data.region != null ? { region: data.region } : {}),\n ...(data.city != null ? { city: data.city } : {}),\n ...(data.ip ? { ipHash: hashIp(data.ip) } : {}),\n ...(data.userAgent ? { userAgentHash: hashUserAgent(data.userAgent) } : {}),\n }\n const visitor = await this.visitors.create(input)\n this.eventBus?.emit('visitor.created', visitor)\n return visitor\n }\n}\n","import type { SafeAdminUser, AdminUser, UpdateUserInput } from '@consenti/types'\nimport { hashPassword } from '../utils/crypto'\nimport type { UserRepo } from '../repositories/user.repo'\nimport type { AuditRepo } from '../repositories/audit.repo'\n\nexport class UserService {\n constructor(\n private users: UserRepo,\n private audit: AuditRepo,\n private tenantId: string = 'default',\n ) {}\n\n private safe(user: AdminUser): SafeAdminUser {\n const { passwordHash: _p, ...rest } = user\n return rest\n }\n\n async create(\n input: { name: string; email: string; password: string; roleId?: string; allowedTenants?: string[] },\n actorId?: string,\n ): Promise<SafeAdminUser> {\n const user = await this.users.create({\n tenantId: this.tenantId,\n name: input.name,\n email: input.email,\n passwordHash: hashPassword(input.password),\n ...(input.allowedTenants ? { allowedTenants: input.allowedTenants } : {}),\n })\n if (input.roleId) await this.users.assignRole(user.id, input.roleId)\n await this.audit.log({\n tenantId: this.tenantId,\n ...(actorId != null ? { userId: actorId } : {}),\n action: 'user.created',\n resourceType: 'user',\n resourceId: user.id,\n newData: this.safe(user),\n })\n return this.safe(user)\n }\n\n async update(\n id: string,\n input: { name?: string; email?: string; isActive?: boolean; password?: string; allowedTenants?: string[] },\n actorId?: string,\n ): Promise<SafeAdminUser> {\n const existing = await this.users.getById(id)\n if (!existing) throw new Error(`User ${id} not found`)\n const data: UpdateUserInput = {}\n if (input.name != null) data.name = input.name\n if (input.email != null) data.email = input.email\n if (input.isActive != null) data.isActive = input.isActive\n if (input.password) data.passwordHash = hashPassword(input.password)\n if (input.allowedTenants != null) data.allowedTenants = input.allowedTenants\n const updated = await this.users.update(id, data)\n await this.audit.log({\n tenantId: this.tenantId,\n ...(actorId != null ? { userId: actorId } : {}),\n action: 'user.updated',\n resourceType: 'user',\n resourceId: id,\n oldData: this.safe(existing),\n newData: this.safe(updated),\n })\n return this.safe(updated)\n }\n\n async delete(id: string, actorId?: string): Promise<void> {\n const existing = await this.users.getById(id)\n await this.users.delete(id)\n await this.audit.log({\n tenantId: this.tenantId,\n ...(actorId != null ? { userId: actorId } : {}),\n action: 'user.deleted',\n resourceType: 'user',\n resourceId: id,\n ...(existing != null ? { oldData: this.safe(existing) } : {}),\n })\n }\n\n async get(id: string): Promise<SafeAdminUser | null> {\n const user = await this.users.getById(id)\n return user ? this.safe(user) : null\n }\n\n async list(): Promise<SafeAdminUser[]> {\n const users = await this.users.list(this.tenantId)\n return users.map(u => this.safe(u))\n }\n\n getRoles(userId: string, tenantId?: string) { return this.users.getRoles(userId, tenantId) }\n assignRole(userId: string, roleId: string, tenantId?: string) { return this.users.assignRole(userId, roleId, tenantId) }\n revokeRole(userId: string, roleId: string, tenantId?: string) { return this.users.revokeRole(userId, roleId, tenantId) }\n}\n","import type { StorageAdapter, AdminUser } from '@consenti/types'\nimport { hashPassword, verifyPassword, signJwt, verifyJwt } from '../utils/crypto'\n\nconst LOCKOUT_WINDOW_MS = 15 * 60_000\nconst MAX_FAILED_ATTEMPTS = 5\n\nexport class LocalAuth {\n private loginAttempts = new Map<string, { count: number; resetAt: number }>()\n\n constructor(\n private storage: StorageAdapter,\n private secret: string,\n ) {\n setInterval(() => {\n const now = Date.now()\n for (const [key, entry] of this.loginAttempts) {\n if (now >= entry.resetAt) this.loginAttempts.delete(key)\n }\n }, LOCKOUT_WINDOW_MS).unref()\n }\n\n async bootstrap(email: string, password: string): Promise<AdminUser | null> {\n const count = await this.storage.countUsers('default')\n if (count > 0) return null\n if (password.length < 12) {\n throw new Error('[Consenti] bootstrap: admin password must be at least 12 characters')\n }\n if (password.length < 16) {\n console.warn('[Consenti] bootstrap: admin password is shorter than 16 characters — consider using a longer password')\n }\n const passwordHash = hashPassword(password)\n const user = await this.storage.createUser({\n tenantId: 'default',\n name: 'Admin',\n email,\n passwordHash,\n })\n await this.storage.assignRole(user.id, 'role_super_admin')\n return user\n }\n\n async login(email: string, password: string): Promise<string | null> {\n const now = Date.now()\n const attempts = this.loginAttempts.get(email)\n if (attempts && now < attempts.resetAt && attempts.count >= MAX_FAILED_ATTEMPTS) return null\n\n const user = await this.storage.getUserByEmail(email)\n if (!user || !user.isActive || !verifyPassword(password, user.passwordHash)) {\n const entry = this.loginAttempts.get(email)\n if (!entry || now >= entry.resetAt) {\n this.loginAttempts.set(email, { count: 1, resetAt: now + LOCKOUT_WINDOW_MS })\n } else {\n entry.count += 1\n }\n return null\n }\n\n this.loginAttempts.delete(email)\n const roles = await this.storage.getUserRoles(user.id)\n const permSets = await Promise.all(roles.map(r => this.storage.getPermissionsForRole(r.id)))\n const permissions = [...new Set(permSets.flat().map(p => p.name))]\n return signJwt(\n {\n sub: user.id,\n email: user.email,\n roles: roles.map(r => r.name),\n permissions,\n allowedTenants: user.allowedTenants ?? [],\n },\n this.secret,\n )\n }\n\n signToken(payload: { sub: string; email: string; roles: string[]; permissions: string[] }): string {\n return signJwt(payload, this.secret)\n }\n\n verify(token: string): Record<string, unknown> | null {\n return verifyJwt(token, this.secret)\n }\n\n async getUser(token: string): Promise<AdminUser | null> {\n const payload = this.verify(token)\n if (!payload) return null\n const id = payload['sub']\n if (typeof id !== 'string') return null\n return this.storage.getUserById(id)\n }\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\n\nexport class PayloadTooLargeError extends Error {\n constructor() { super('Payload Too Large') }\n}\n\nexport function getIp(req: IncomingMessage, trustedProxies?: string[]): string {\n const remoteIp = req.socket?.remoteAddress ?? ''\n if (!trustedProxies?.length) return remoteIp\n if (!trustedProxies.includes(remoteIp)) return remoteIp\n const fwd = req.headers['x-forwarded-for']\n if (typeof fwd === 'string') return fwd.split(',')[0]?.trim() ?? remoteIp\n if (Array.isArray(fwd)) return fwd[0]?.trim() ?? remoteIp\n return remoteIp\n}\n\nexport function json(status: number, data: unknown): Response {\n return new Response(JSON.stringify(data), {\n status,\n headers: { 'Content-Type': 'application/json' },\n })\n}\n\nexport async function parseJsonBody<T = unknown>(request: Request): Promise<T | null> {\n const ct = request.headers.get('content-type') ?? ''\n if (!ct.includes('application/json')) return null\n try {\n return await request.json() as T\n } catch {\n return null\n }\n}\n\nexport function getQueryParam(url: URL, key: string): string | undefined {\n const val = url.searchParams.get(key)\n return val ?? undefined\n}\n\nexport function getQueryInt(url: URL, key: string, fallback: number): number {\n const val = url.searchParams.get(key)\n if (!val) return fallback\n const n = parseInt(val, 10)\n return isNaN(n) ? fallback : n\n}\n\nexport async function nodeRequestToFetch(\n req: IncomingMessage,\n maxBodyBytes = 1_048_576,\n trustedProxies?: string[],\n): Promise<Request> {\n const rawProto = req.headers['x-forwarded-proto']\n const proto = rawProto === 'https' ? 'https' : 'http'\n const host = req.headers['host'] ?? 'localhost'\n const url = new URL(req.url ?? '/', `${proto}://${host}`)\n\n const headers = new Headers()\n for (const [key, value] of Object.entries(req.headers)) {\n if (!value) continue\n if (Array.isArray(value)) {\n for (const v of value) headers.append(key, v)\n } else {\n headers.set(key, value)\n }\n }\n headers.set('x-real-ip', getIp(req, trustedProxies))\n\n let body: BodyInit | null = null\n const method = (req.method ?? 'GET').toUpperCase()\n if (method !== 'GET' && method !== 'HEAD') {\n const chunks: Buffer[] = []\n let totalBytes = 0\n for await (const chunk of req) {\n totalBytes += (chunk as Buffer).length\n if (totalBytes > maxBodyBytes) throw new PayloadTooLargeError()\n chunks.push(chunk as Buffer)\n }\n if (chunks.length > 0) body = Buffer.concat(chunks)\n }\n\n return new Request(url.toString(), { method, headers, body })\n}\n\nexport async function fetchResponseToNode(response: Response, res: ServerResponse): Promise<void> {\n res.statusCode = response.status\n const setCookies: string[] =\n typeof (response.headers as { getSetCookie?: () => string[] }).getSetCookie === 'function'\n ? (response.headers as unknown as { getSetCookie: () => string[] }).getSetCookie()\n : (response.headers.get('set-cookie') ? [response.headers.get('set-cookie')!] : [])\n response.headers.forEach((value, key) => {\n if (key.toLowerCase() === 'set-cookie') return\n res.setHeader(key, value)\n })\n for (const cookie of setCookies) {\n res.appendHeader('set-cookie', cookie)\n }\n if (response.body) {\n const reader = response.body.getReader()\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n res.write(Buffer.from(value))\n }\n } finally {\n reader.releaseLock()\n }\n res.end()\n } else {\n res.end()\n }\n}\n","export function errorResponse(status: number, message: string, details?: unknown): Response {\n const body: Record<string, unknown> = { error: message }\n if (details != null && process.env['NODE_ENV'] !== 'production') {\n body['details'] = details\n }\n return new Response(JSON.stringify(body), {\n status,\n headers: { 'Content-Type': 'application/json' },\n })\n}\n\nexport async function withErrorHandler(fn: () => Promise<Response>): Promise<Response> {\n try {\n return await fn()\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Internal Server Error'\n return errorResponse(500, 'Internal Server Error',\n process.env['NODE_ENV'] !== 'production' ? message : undefined)\n }\n}\n","import type { ProfileService } from '../../services/profile.service'\nimport type { GeoResolverService } from '../../services/geo-resolver.service'\nimport { json } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nconst CACHE_CONTROL = 'public, max-age=3600, stale-while-revalidate=60'\nconst JSON_HEADERS = { 'Content-Type': 'application/json', 'Cache-Control': CACHE_CONTROL }\n\nfunction serveJsonFile(filePath: string): Response {\n const content = readFileSync(filePath, 'utf8')\n return new Response(content, { headers: JSON_HEADERS })\n}\n\nfunction redirectToDefault(basePath: string, tenantId: string, complianceGroup: string): Response {\n return new Response(null, {\n status: 303,\n headers: { Location: `${basePath}/profiles/${tenantId}/${complianceGroup}/default` },\n })\n}\n\nexport function buildProfileRoutes(\n profiles: ProfileService,\n geoResolver?: GeoResolverService,\n profilesDir?: string,\n basePath = '',\n) {\n return {\n // Static file route — primary hot-serve path, zero DB when file exists\n 'GET /profiles/:tenantId/:complianceGroupOrProfileId/:locale': async (\n _req: Request,\n params: Record<string, string>,\n ): Promise<Response> =>\n withErrorHandler(async () => {\n const { tenantId, complianceGroupOrProfileId, locale } = params as Record<string, string>\n if (!tenantId || !complianceGroupOrProfileId || !locale) return errorResponse(400, 'Missing path parameters')\n\n if (profilesDir) {\n const filePath = join(profilesDir, tenantId, complianceGroupOrProfileId, `${locale}.json`)\n if (existsSync(filePath)) return serveJsonFile(filePath)\n // Locale not found → 303 to default\n const defaultPath = join(profilesDir, tenantId, complianceGroupOrProfileId, 'default.json')\n if (existsSync(defaultPath)) return redirectToDefault(basePath, tenantId, complianceGroupOrProfileId)\n }\n\n // Fall back to DB-resolved profile (for preview of inactive/versioned profiles)\n const result = await profiles.getResolved(complianceGroupOrProfileId, locale)\n if (!result) return errorResponse(404, 'Profile not found')\n return json(200, result)\n }),\n\n // Versioned profile file route (for dashboard preview)\n 'GET /profiles/:tenantId/:profileId/:version/:locale': async (\n _req: Request,\n params: Record<string, string>,\n ): Promise<Response> =>\n withErrorHandler(async () => {\n const { tenantId, profileId, version, locale } = params as Record<string, string>\n if (!tenantId || !profileId || !version || !locale) return errorResponse(400, 'Missing path parameters')\n const ver = parseInt(version, 10)\n if (isNaN(ver) || ver < 1) return errorResponse(400, 'Invalid version')\n\n if (profilesDir) {\n const filePath = join(profilesDir, tenantId, profileId, version, `${locale}.json`)\n if (existsSync(filePath)) return serveJsonFile(filePath)\n const defaultPath = join(profilesDir, tenantId, profileId, version, 'default.json')\n if (existsSync(defaultPath)) return serveJsonFile(defaultPath)\n }\n\n const content = profiles.getVersionFile(profileId, ver, locale)\n if (!content) return errorResponse(404, 'Version not found')\n return new Response(content, { headers: JSON_HEADERS })\n }),\n\n // Geo-resolve endpoint — for compliance.type='auto' widgets\n 'GET /resolve-profile': async (request: Request, _params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n if (!geoResolver) return errorResponse(501, 'Geo compliance routing not configured')\n const url = new URL(request.url)\n\n const ip =\n request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ??\n request.headers.get('x-real-ip') ??\n ''\n const timezone = url.searchParams.get('tz') ?? ''\n const language =\n url.searchParams.get('lang') ??\n request.headers.get('accept-language') ??\n ''\n const requestedLocale = url.searchParams.get('locale') ?? ''\n\n const geo = await geoResolver.resolve({ ip, language, timezone })\n\n if (!geo.complianceGroup) {\n return errorResponse(404, 'Could not resolve compliance group for this location')\n }\n\n const profile = await profiles.findActiveByComplianceGroup(geo.complianceGroup)\n if (!profile) {\n return errorResponse(404, `No active profile found for compliance group: ${geo.complianceGroup}`)\n }\n\n // Determine best locale\n const pj = profile.profileJson as { localeContents?: Record<string, unknown>; defaultLocale?: string }\n const availableLocales = pj.localeContents ? Object.keys(pj.localeContents) : []\n let resolvedLocale = profile.defaultLocale\n if (requestedLocale && availableLocales.includes(requestedLocale)) {\n resolvedLocale = requestedLocale\n } else if (geo.locale && availableLocales.includes(geo.locale)) {\n resolvedLocale = geo.locale\n }\n\n const complianceGroup = geo.complianceGroup\n const tenantId = profile.tenantId\n\n let warning: string | undefined\n let filePath = profilesDir\n ? join(profilesDir, tenantId, complianceGroup, `${resolvedLocale}.json`)\n : ''\n\n if (profilesDir && !existsSync(filePath)) {\n const defaultPath = join(profilesDir, tenantId, complianceGroup, 'default.json')\n if (existsSync(defaultPath)) {\n resolvedLocale = profile.defaultLocale\n warning = 'locale_not_found'\n filePath = defaultPath\n }\n }\n\n const path = `${basePath}/profiles/${tenantId}/${complianceGroup}/${resolvedLocale}`\n\n return json(200, {\n path,\n resolvedLocale,\n resolvedComplianceGroup: complianceGroup,\n profileId: profile.id,\n version: profile.version,\n ...(warning ? { warning } : {}),\n })\n }),\n\n // Legacy: single-param profile route (by ID)\n 'GET /profiles/:id': async (_request: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const id = params['id']\n if (!id) return errorResponse(400, 'Missing profile id')\n const result = await profiles.getResolved(id)\n if (!result) return errorResponse(404, 'Profile not found')\n return json(200, result)\n }),\n\n 'GET /profiles/:id/:locale': async (_request: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { id, locale } = params as Record<string, string>\n if (!id) return errorResponse(400, 'Missing profile id')\n const result = await profiles.getResolved(id, locale)\n if (!result) return errorResponse(404, 'Profile not found')\n return json(200, result)\n }),\n\n // Geo-resolved auto route (legacy path)\n 'GET /profiles/auto/:locale': async (request: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n if (!geoResolver) return errorResponse(501, 'Geo compliance routing not configured')\n const locale = params['locale'] ?? 'en'\n const url = new URL(request.url)\n const ip =\n request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ??\n request.headers.get('x-real-ip') ?? ''\n const timezone = url.searchParams.get('tz') ?? ''\n const language = request.headers.get('accept-language') ?? url.searchParams.get('lang') ?? ''\n const geo = await geoResolver.resolve({ ip, language, timezone })\n if (!geo.complianceGroup) return errorResponse(404, 'Could not resolve compliance group for this location')\n const profile = await profiles.findActiveByComplianceGroup(geo.complianceGroup)\n if (!profile) return errorResponse(404, `No active profile found for compliance group: ${geo.complianceGroup}`)\n const result = await profiles.getResolved(profile.id, locale)\n if (!result) return errorResponse(404, 'Profile not found')\n return json(200, { ...result, resolvedComplianceGroup: geo.complianceGroup })\n }),\n }\n}\n","import type { ConsentDbRecord, ConsentValue } from '@consenti/types'\n\nfunction buildCookieValue(consentJson: ConsentValue, timestamp: string): string {\n const entries = Object.entries(consentJson)\n .map(([k, v]) => `${k}:${v}`)\n .join('|')\n return `ConsentTimestamp:${timestamp}::${entries}`\n}\n\nexport function buildConsentSetCookie(record: ConsentDbRecord): string {\n const name = `consenti_${record.visitorId}_${record.profileId}`\n const value = buildCookieValue(record.consentJson, record.createdAt)\n const secure = process.env['NODE_ENV'] === 'production' ? '; Secure' : ''\n return `${name}=${value}; SameSite=Lax${secure}; Path=/; Max-Age=31536000`\n}\n\nexport function buildExpireSetCookie(visitorId: string, profileId: string): string {\n const name = `consenti_${visitorId}_${profileId}`\n const secure = process.env['NODE_ENV'] === 'production' ? '; Secure' : ''\n return `${name}=; SameSite=Lax${secure}; Path=/; Max-Age=0`\n}\n","function matchesAllowedOrigin(origin: string, allowedOrigins: string[]): boolean {\n let hostname: string\n try {\n hostname = new URL(origin).hostname\n } catch {\n return false\n }\n return allowedOrigins.some(pattern => {\n if (pattern.startsWith('*.')) {\n const suffix = pattern.slice(1) // '.example.com'\n return hostname === pattern.slice(2) || hostname.endsWith(suffix)\n }\n return hostname === pattern\n })\n}\n\nexport function buildCorsHeaders(origin: string | null, allowedOrigins?: string[]): Record<string, string> {\n let allowOrigin = origin ?? '*'\n if (allowedOrigins && allowedOrigins.length > 0 && origin) {\n allowOrigin = matchesAllowedOrigin(origin, allowedOrigins) ? origin : 'null'\n }\n return {\n 'Access-Control-Allow-Origin': allowOrigin,\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n 'Access-Control-Max-Age': '86400',\n }\n}\n\nexport function handleCors(request: Request): Response | null {\n if (request.method === 'OPTIONS') {\n const origin = request.headers.get('origin')\n return new Response(null, {\n status: 204,\n headers: buildCorsHeaders(origin),\n })\n }\n return null\n}\n\nexport function withCors(response: Response, request: Request): Response {\n const origin = request.headers.get('origin')\n const cors = buildCorsHeaders(origin)\n const newHeaders = new Headers(response.headers)\n for (const [k, v] of Object.entries(cors)) newHeaders.set(k, v)\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: newHeaders,\n })\n}\n\nexport function checkOriginAllowed(request: Request, allowedOrigins: string[]): boolean {\n if (allowedOrigins.length === 0) return true\n const origin = request.headers.get('origin')\n if (!origin) return true // non-browser / server-side calls always allowed\n return matchesAllowedOrigin(origin, allowedOrigins)\n}\n\nconst CSP = [\n \"default-src 'self'\",\n \"script-src 'self' https://unpkg.com\",\n \"style-src 'self' https://unpkg.com 'unsafe-inline'\",\n \"img-src 'self' data:\",\n \"font-src 'self'\",\n \"connect-src 'self'\",\n \"frame-ancestors 'none'\",\n \"base-uri 'self'\",\n \"form-action 'self'\",\n].join('; ')\n\nexport function addSecurityHeaders(res: Response): Response {\n const h = new Headers(res.headers)\n h.set('X-Content-Type-Options', 'nosniff')\n h.set('X-Frame-Options', 'DENY')\n h.set('Referrer-Policy', 'no-referrer')\n h.set('Permissions-Policy', 'interest-cohort=()')\n h.set('Content-Security-Policy', CSP)\n // Browsers only honour HSTS over HTTPS; sending it over HTTP is harmless.\n h.set('Strict-Transport-Security', 'max-age=63072000; includeSubDomains; preload')\n return new Response(res.body, { status: res.status, statusText: res.statusText, headers: h })\n}\n","import type { CreateConsentInput, UpdateConsentInput, ConsentValue } from '@consenti/types'\n\nexport interface ValidationResult {\n valid: boolean\n error?: string\n}\n\nconst VALID_STATUSES = new Set(['granted', 'denied', 'objected'])\n\nfunction validateConsentJsonValues(consentJson: unknown): ValidationResult {\n const entries = Object.entries(consentJson as Record<string, unknown>)\n for (const [key, val] of entries) {\n if (!key) return { valid: false, error: 'consentJson keys must be non-empty strings' }\n if (!VALID_STATUSES.has(val as string)) {\n return { valid: false, error: `consentJson value \"${String(val)}\" is invalid; must be granted, denied, or objected` }\n }\n }\n return { valid: true }\n}\n\nexport function validateCreateConsent(body: unknown): ValidationResult {\n if (!body || typeof body !== 'object') return { valid: false, error: 'Request body must be a JSON object' }\n const b = body as Record<string, unknown>\n if (typeof b['profileId'] !== 'string' || !b['profileId']) return { valid: false, error: 'profileId is required' }\n if (!b['consentJson'] || typeof b['consentJson'] !== 'object' || Array.isArray(b['consentJson'])) {\n return { valid: false, error: 'consentJson must be an object' }\n }\n return validateConsentJsonValues(b['consentJson'])\n}\n\nexport function validateUpdateConsent(body: unknown): ValidationResult {\n if (!body || typeof body !== 'object') return { valid: false, error: 'Request body must be a JSON object' }\n const b = body as Record<string, unknown>\n if (!b['consentJson'] || typeof b['consentJson'] !== 'object' || Array.isArray(b['consentJson'])) {\n return { valid: false, error: 'consentJson must be an object' }\n }\n return validateConsentJsonValues(b['consentJson'])\n}\n\nexport function castCreateConsent(body: Record<string, unknown>, visitorId: string, tenantId: string): CreateConsentInput {\n return {\n tenantId,\n visitorId,\n profileId: body['profileId'] as string,\n profileVersion: typeof body['profileVersion'] === 'number' ? body['profileVersion'] : 1,\n locale: typeof body['locale'] === 'string' ? body['locale'] : 'en',\n consentJson: body['consentJson'] as ConsentValue,\n gpcDetected: Boolean(body['gpcDetected']),\n source: (body['source'] as CreateConsentInput['source']) ?? 'banner',\n }\n}\n\nexport function castUpdateConsent(body: Record<string, unknown>): UpdateConsentInput {\n const result: UpdateConsentInput = {\n consentJson: body['consentJson'] as ConsentValue,\n }\n if (typeof body['locale'] === 'string') result.locale = body['locale']\n if (body['gpcDetected'] != null) result.gpcDetected = Boolean(body['gpcDetected'])\n return result\n}\n","import type { ConsentService } from '../../services/consent.service'\nimport type { VisitorService } from '../../services/visitor.service'\nimport type { ProfileService } from '../../services/profile.service'\nimport { parseJsonBody } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { buildConsentSetCookie, buildExpireSetCookie } from '../../utils/cookie'\nimport { checkOriginAllowed } from '../../middleware/cors.middleware'\nimport {\n validateCreateConsent, validateUpdateConsent,\n castCreateConsent, castUpdateConsent,\n} from '../../validators/consent.validator'\nimport { randomUUID } from '../../utils/crypto'\n\n// Verify that the request's cookie contains a consenti_<visitorId>_* token,\n// proving the caller is the actual visitor who originally submitted consent.\nfunction assertVisitorOwnership(request: Request, visitorId: string): Response | null {\n const cookieHeader = request.headers.get('cookie') ?? ''\n const prefix = `consenti_${visitorId}_`\n const owned = cookieHeader.split(';').some(c => {\n const trimmed = c.trim()\n if (!trimmed.startsWith(prefix)) return false\n const val = trimmed.slice(trimmed.indexOf('=') + 1)\n return val.startsWith('ConsentTimestamp:')\n })\n if (!owned) return errorResponse(403, 'Forbidden')\n return null\n}\n\nexport function buildConsentRoutes(\n consents: ConsentService,\n visitors: VisitorService,\n profiles: ProfileService,\n resolveTenantId: (req: Request) => Promise<string> = async () => 'default',\n) {\n return {\n 'POST /consent': async (request: Request, _params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const body = await parseJsonBody(request)\n const validation = validateCreateConsent(body)\n if (!validation.valid) return errorResponse(400, validation.error ?? 'Invalid request')\n\n const b = body as Record<string, unknown>\n const profileId = typeof b['profileId'] === 'string' ? b['profileId'] : null\n if (!profileId) return errorResponse(400, 'profileId is required')\n\n // Layer 1: verify the profileId is real — blocks all requests with unknown profiles\n const profile = await profiles.get(profileId)\n if (!profile) return errorResponse(404, 'Profile not found')\n\n // Layer 3: enforce the profile's allowed-domains list\n const pjConfig = profile.profileJson as { allowedOrigins?: string[] }\n const allowedOrigins = pjConfig.allowedOrigins ?? []\n if (!checkOriginAllowed(request, allowedOrigins)) {\n return errorResponse(403, 'Origin not allowed for this profile')\n }\n\n const visitorId = typeof b['visitorId'] === 'string' ? b['visitorId'] : randomUUID()\n const ip = request.headers.get('x-real-ip') ?? ''\n const ua = request.headers.get('user-agent') ?? ''\n const tenantId = await resolveTenantId(request)\n\n await visitors.upsert({ visitorId, ip, userAgent: ua })\n const input = castCreateConsent(b, visitorId, tenantId)\n const record = await consents.create(input)\n\n const setCookie = buildConsentSetCookie(record)\n return new Response(JSON.stringify(record), {\n status: 201,\n headers: {\n 'Content-Type': 'application/json',\n 'Set-Cookie': setCookie,\n },\n })\n }),\n\n 'PUT /consent/:visitorId': async (request: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const visitorId = params['visitorId']\n if (!visitorId) return errorResponse(400, 'Missing visitorId')\n\n // Layer 2: only the visitor's own browser may update their consent\n const ownershipError = assertVisitorOwnership(request, visitorId)\n if (ownershipError) return ownershipError\n\n const body = await parseJsonBody(request)\n const validation = validateUpdateConsent(body)\n if (!validation.valid) return errorResponse(400, validation.error ?? 'Invalid request')\n\n const input = castUpdateConsent(body as Record<string, unknown>)\n const record = await consents.update(visitorId, input)\n\n const setCookie = buildConsentSetCookie(record)\n return new Response(JSON.stringify(record), {\n status: 200,\n headers: {\n 'Content-Type': 'application/json',\n 'Set-Cookie': setCookie,\n },\n })\n }),\n\n 'GET /consent/:visitorId': async (request: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const visitorId = params['visitorId']\n if (!visitorId) return errorResponse(400, 'Missing visitorId')\n\n // Layer 2: only the visitor's own browser may read their consent\n const ownershipError = assertVisitorOwnership(request, visitorId)\n if (ownershipError) return ownershipError\n\n const record = await consents.get(visitorId)\n if (!record) return errorResponse(404, 'Consent not found')\n return new Response(JSON.stringify(record), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n })\n }),\n\n 'GET /consent/:visitorId/verify': async (request: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const visitorId = params['visitorId']\n if (!visitorId) return errorResponse(400, 'Missing visitorId')\n\n // Layer 2: cookie ownership (browser calls); server-side callers use admin auth upstream\n const ownershipError = assertVisitorOwnership(request, visitorId)\n if (ownershipError) return ownershipError\n\n const result = await consents.verify(visitorId)\n return new Response(JSON.stringify(result), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n })\n }),\n\n 'DELETE /consent/:visitorId': async (request: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const visitorId = params['visitorId']\n if (!visitorId) return errorResponse(400, 'Missing visitorId')\n\n // Layer 2: only the visitor's own browser may erase their consent\n const ownershipError = assertVisitorOwnership(request, visitorId)\n if (ownershipError) return ownershipError\n\n const existing = await consents.get(visitorId)\n await consents.erase(visitorId)\n const headers: Record<string, string> = { 'Content-Type': 'application/json' }\n if (existing) {\n headers['Set-Cookie'] = buildExpireSetCookie(visitorId, existing.profileId)\n }\n return new Response(JSON.stringify({ success: true }), { status: 200, headers })\n }),\n }\n}\n","import { randomBytes } from 'node:crypto'\nimport type { StorageAdapter, AuthConfig } from '@consenti/types'\nimport { json, parseJsonBody } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate } from '../../middleware/auth.middleware'\nimport type { RateLimiter } from '../../middleware/rate-limit.middleware'\nimport type { LocalAuth } from '../../auth/local.auth'\nimport {\n generatePkce, discoverOidcEndpoints, buildAuthorizationUrl,\n exchangeOidcCode, verifyOidcIdToken, extractEmailFromClaims,\n extractRolesFromClaims, storePkceState, consumePkceState,\n} from '../../auth/oidc.auth'\nimport { buildSamlMetadataXml, validateSamlResponse } from '../../auth/saml.auth'\nimport { generateTotpSecret, verifyTotp, totpQrUrl } from '../../auth/totp'\n\nfunction base64url(buf: Buffer): string {\n return buf.toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '')\n}\n\nexport function buildAdminAuthRoutes(\n localAuth: LocalAuth,\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n authLimiter?: RateLimiter | null,\n) {\n function checkAuthLimit(req: Request): Response | null {\n if (!authLimiter) return null\n const ip = req.headers.get('x-real-ip') ?? ''\n if (!authLimiter.checkRequest(ip)) return errorResponse(429, 'Too Many Requests')\n return null\n }\n\n return {\n 'POST /auth/login': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const limited = checkAuthLimit(req)\n if (limited) return limited\n if (authConfig.mode !== 'local') return errorResponse(400, 'Login not available in this auth mode')\n const body = await parseJsonBody(req)\n if (!body || typeof body !== 'object') return errorResponse(400, 'Invalid body')\n const b = body as Record<string, unknown>\n if (typeof b['email'] !== 'string' || typeof b['password'] !== 'string') {\n return errorResponse(400, 'email and password are required')\n }\n const token = await localAuth.login(b['email'], b['password'])\n if (!token) return errorResponse(401, 'Invalid credentials')\n return json(200, { token })\n }),\n\n 'GET /auth/me': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const user = await authenticate(req, storage, authConfig, secret)\n if (!user) return errorResponse(401, 'Unauthorized')\n const dbUser = await storage.getUserById(user.sub)\n if (!dbUser) return errorResponse(401, 'User not found')\n const roles = await storage.getUserRoles(dbUser.id)\n return json(200, {\n id: dbUser.id,\n email: dbUser.email,\n name: dbUser.name,\n isActive: dbUser.isActive,\n totpEnabled: dbUser.totpEnabled ?? false,\n roles: roles.map(r => r.name),\n permissions: user.permissions,\n })\n }),\n\n 'POST /auth/logout': async (_req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => json(200, { success: true })),\n\n // ── OIDC ────────────────────────────────────────────────────────────────────\n\n 'GET /auth/oidc/authorize': async (_req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n if (authConfig.mode !== 'oidc' || !authConfig.oidc) return errorResponse(400, 'OIDC not configured')\n const endpoints = await discoverOidcEndpoints(authConfig.oidc.issuer)\n const state = base64url(randomBytes(16))\n const nonce = base64url(randomBytes(16))\n const { verifier, challenge } = generatePkce()\n storePkceState(state, verifier, nonce)\n const url = buildAuthorizationUrl(authConfig.oidc, endpoints.authorization_endpoint, state, nonce, challenge)\n return new Response(null, { status: 302, headers: { Location: url } })\n }),\n\n 'GET /auth/oidc/callback': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n if (authConfig.mode !== 'oidc' || !authConfig.oidc) return errorResponse(400, 'OIDC not configured')\n const url = new URL(req.url)\n const code = url.searchParams.get('code')\n const state = url.searchParams.get('state')\n if (!code || !state) return errorResponse(400, 'Missing code or state')\n const pkce = consumePkceState(state)\n if (!pkce) return errorResponse(400, 'Invalid or expired state')\n const endpoints = await discoverOidcEndpoints(authConfig.oidc.issuer)\n const tokens = await exchangeOidcCode(authConfig.oidc, endpoints.token_endpoint, code, pkce.verifier)\n const claims = await verifyOidcIdToken(tokens.id_token, endpoints.jwks_uri)\n const email = extractEmailFromClaims(claims, authConfig.oidc.claimsMapping)\n const roles = extractRolesFromClaims(claims, authConfig.oidc.claimsMapping)\n // Upsert admin user from OIDC claims\n let user = await storage.getUserByEmail(email)\n if (!user) {\n user = await storage.createUser({ tenantId: 'default', name: email, email, passwordHash: '' })\n }\n if (roles.length > 0) {\n const allRoles = await storage.getRoles('default')\n for (const roleName of roles) {\n const role = allRoles.find(r => r.name === roleName)\n if (role) await storage.assignRole(user.id, role.id).catch(() => {})\n }\n }\n const userRoles = await storage.getUserRoles(user.id)\n const permissions: string[] = []\n for (const role of userRoles) {\n const perms = await storage.getPermissionsForRole(role.id)\n permissions.push(...perms.map(p => p.name))\n }\n const token = localAuth.signToken({\n sub: user.id, email: user.email,\n roles: userRoles.map(r => r.name),\n permissions: [...new Set(permissions)],\n })\n return json(200, { token })\n }),\n\n // ── SAML ────────────────────────────────────────────────────────────────────\n\n 'GET /auth/saml/metadata': async (_req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n if (authConfig.mode !== 'saml' || !authConfig.saml) return errorResponse(400, 'SAML not configured')\n const xml = buildSamlMetadataXml(authConfig.saml)\n return new Response(xml, { status: 200, headers: { 'Content-Type': 'application/xml' } })\n }),\n\n 'POST /auth/saml/acs': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const limited = checkAuthLimit(req)\n if (limited) return limited\n if (authConfig.mode !== 'saml' || !authConfig.saml) return errorResponse(400, 'SAML not configured')\n const params = new URLSearchParams(await req.text())\n const samlResponse = params.get('SAMLResponse')\n if (typeof samlResponse !== 'string') return errorResponse(400, 'Missing SAMLResponse')\n const info = await validateSamlResponse(samlResponse, authConfig.saml)\n if (!info) return errorResponse(401, 'SAML validation failed')\n let user = await storage.getUserByEmail(info.email)\n if (!user) {\n user = await storage.createUser({ tenantId: 'default', name: info.email, email: info.email, passwordHash: '' })\n }\n const userRoles = await storage.getUserRoles(user.id)\n const permissions: string[] = []\n for (const role of userRoles) {\n const perms = await storage.getPermissionsForRole(role.id)\n permissions.push(...perms.map(p => p.name))\n }\n const token = localAuth.signToken({\n sub: user.id, email: user.email,\n roles: userRoles.map(r => r.name),\n permissions: [...new Set(permissions)],\n })\n return json(200, { token })\n }),\n\n // ── TOTP ────────────────────────────────────────────────────────────────────\n\n 'POST /auth/totp/setup': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const user = await authenticate(req, storage, authConfig, secret)\n if (!user) return errorResponse(401, 'Unauthorized')\n const dbUser = await storage.getUserById(user.sub)\n if (!dbUser) return errorResponse(401, 'User not found')\n const totpSecret = generateTotpSecret()\n const qrUrl = totpQrUrl(totpSecret, dbUser.email)\n await storage.updateUser(dbUser.id, { totpSecret, totpEnabled: false })\n return json(200, { qrUrl, message: 'Scan QR code, then verify with POST /auth/totp/verify' })\n }),\n\n 'POST /auth/totp/verify': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const limited = checkAuthLimit(req)\n if (limited) return limited\n const user = await authenticate(req, storage, authConfig, secret)\n if (!user) return errorResponse(401, 'Unauthorized')\n const dbUser = await storage.getUserById(user.sub)\n if (!dbUser) return errorResponse(401, 'User not found')\n if (!dbUser.totpSecret) return errorResponse(400, 'TOTP not set up — call POST /auth/totp/setup first')\n const body = await parseJsonBody(req)\n if (!body || typeof body !== 'object') return errorResponse(400, 'Invalid body')\n const b = body as Record<string, unknown>\n if (typeof b['token'] !== 'string') return errorResponse(400, 'token is required')\n if (!verifyTotp(dbUser.totpSecret, b['token'])) return errorResponse(400, 'Invalid TOTP token')\n await storage.updateUser(dbUser.id, { totpEnabled: true })\n return json(200, { success: true, message: 'TOTP enabled successfully' })\n }),\n\n 'POST /auth/totp/disable': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const user = await authenticate(req, storage, authConfig, secret)\n if (!user) return errorResponse(401, 'Unauthorized')\n const dbUser = await storage.getUserById(user.sub)\n if (!dbUser) return errorResponse(401, 'User not found')\n await storage.updateUser(dbUser.id, { totpSecret: null, totpEnabled: false })\n return json(200, { success: true, message: 'TOTP disabled' })\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig } from '@consenti/types'\nimport { verifyJwt } from '../utils/crypto'\nimport { errorResponse } from './error.middleware'\n\nexport interface AuthenticatedUser {\n sub: string\n email: string\n roles: string[]\n permissions: string[]\n allowedTenants: string[] // empty = all tenants\n}\n\nexport async function authenticate(\n req: Request,\n storage: StorageAdapter,\n config: AuthConfig,\n secret: string,\n): Promise<AuthenticatedUser | null> {\n const auth = req.headers.get('authorization')\n const token = auth?.startsWith('Bearer ') ? auth.slice(7) : null\n if (!token) return null\n\n if (config.mode === 'local' || config.mode === 'jwt') {\n const payload = verifyJwt(token, secret)\n if (!payload) return null\n const sub = payload['sub']\n const email = payload['email']\n const roles = payload['roles']\n const permissions = payload['permissions']\n const allowedTenants = payload['allowedTenants']\n if (typeof sub !== 'string' || typeof email !== 'string') return null\n return {\n sub,\n email,\n roles: Array.isArray(roles) ? (roles as string[]) : [],\n permissions: Array.isArray(permissions) ? (permissions as string[]) : [],\n allowedTenants: Array.isArray(allowedTenants) ? (allowedTenants as string[]) : [],\n }\n }\n\n if (config.mode === 'custom' && config.validateUser) {\n const user = await config.validateUser(req)\n if (!user) return null\n const roles = await storage.getUserRoles(user.id)\n const permSets = await Promise.all(roles.map(r => storage.getPermissionsForRole(r.id)))\n const permissions = [...new Set(permSets.flat().map(p => p.name))]\n return {\n sub: user.id,\n email: user.email,\n roles: roles.map(r => r.name),\n permissions,\n allowedTenants: [],\n }\n }\n\n return null\n}\n\nexport function authError(\n user: AuthenticatedUser | null,\n permission?: string,\n): Response | null {\n if (!user) return errorResponse(401, 'Unauthorized')\n if (permission && !user.permissions.includes(permission)) return errorResponse(403, 'Forbidden')\n return null\n}\n","import { randomBytes, createHash } from 'node:crypto'\nimport type { OidcConfig } from '@consenti/types'\n\nfunction base64url(buf: Buffer): string {\n return buf.toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '')\n}\n\nfunction base64urlDecode(s: string): string {\n return Buffer.from(s.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf8')\n}\n\nexport interface PkceChallenge {\n verifier: string\n challenge: string\n}\n\nexport function generatePkce(): PkceChallenge {\n const verifier = base64url(randomBytes(32))\n const challenge = base64url(createHash('sha256').update(verifier).digest())\n return { verifier, challenge }\n}\n\ninterface OidcEndpoints {\n authorization_endpoint: string\n token_endpoint: string\n userinfo_endpoint?: string\n jwks_uri: string\n}\n\nexport async function discoverOidcEndpoints(issuer: string): Promise<OidcEndpoints> {\n const res = await fetch(`${issuer}/.well-known/openid-configuration`, {\n signal: AbortSignal.timeout(10_000),\n })\n if (!res.ok) throw new Error(`OIDC discovery failed for ${issuer}: ${res.status}`)\n return res.json() as Promise<OidcEndpoints>\n}\n\nexport function buildAuthorizationUrl(\n config: OidcConfig,\n authorizationEndpoint: string,\n state: string,\n nonce: string,\n codeChallenge: string,\n): string {\n const params = new URLSearchParams({\n response_type: 'code',\n client_id: config.clientId,\n redirect_uri: config.redirectUri,\n scope: 'openid email profile',\n state,\n nonce,\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n })\n return `${authorizationEndpoint}?${params.toString()}`\n}\n\ninterface TokenResponse {\n id_token: string\n access_token: string\n token_type: string\n expires_in?: number\n}\n\nexport async function exchangeOidcCode(\n config: OidcConfig,\n tokenEndpoint: string,\n code: string,\n codeVerifier: string,\n): Promise<TokenResponse> {\n const body = new URLSearchParams({\n grant_type: 'authorization_code',\n client_id: config.clientId,\n client_secret: config.clientSecret,\n redirect_uri: config.redirectUri,\n code,\n code_verifier: codeVerifier,\n })\n const res = await fetch(tokenEndpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: body.toString(),\n signal: AbortSignal.timeout(10_000),\n })\n if (!res.ok) {\n const err = await res.text()\n throw new Error(`OIDC token exchange failed: ${err}`)\n }\n return res.json() as Promise<TokenResponse>\n}\n\nexport interface OidcClaims {\n sub: string\n email?: string\n name?: string\n [key: string]: unknown\n}\n\nexport async function verifyOidcIdToken(idToken: string, jwksUri: string): Promise<OidcClaims> {\n const parts = idToken.split('.')\n if (parts.length !== 3) throw new Error('Invalid ID token format')\n\n const header = JSON.parse(base64urlDecode(parts[0]!)) as { kid?: string; alg?: string }\n const alg = header.alg ?? 'RS256'\n\n const res = await fetch(jwksUri, { signal: AbortSignal.timeout(10_000) })\n if (!res.ok) throw new Error(`Failed to fetch JWKS: ${res.status}`)\n type JwkEntry = JsonWebKey & { kid?: string; use?: string }\n const jwks = await res.json() as { keys: JwkEntry[] }\n\n const jwk: JwkEntry | undefined = header.kid\n ? jwks.keys.find(k => k.kid === header.kid)\n : (jwks.keys.find(k => k.use === 'sig') ?? jwks.keys[0])\n if (!jwk) throw new Error('No matching key in JWKS')\n\n let cryptoKey: CryptoKey\n if (alg === 'RS256' || alg === 'RS384' || alg === 'RS512') {\n const hashName = alg === 'RS256' ? 'SHA-256' : alg === 'RS384' ? 'SHA-384' : 'SHA-512'\n cryptoKey = await globalThis.crypto.subtle.importKey(\n 'jwk', jwk, { name: 'RSASSA-PKCS1-v1_5', hash: { name: hashName } }, false, ['verify'],\n )\n } else if (alg === 'ES256' || alg === 'ES384' || alg === 'ES512') {\n const namedCurve = alg === 'ES256' ? 'P-256' : alg === 'ES384' ? 'P-384' : 'P-521'\n cryptoKey = await globalThis.crypto.subtle.importKey(\n 'jwk', jwk, { name: 'ECDSA', namedCurve }, false, ['verify'],\n )\n } else {\n throw new Error(`Unsupported OIDC token algorithm: ${alg}`)\n }\n\n const sigInput = new TextEncoder().encode(`${parts[0]}.${parts[1]}`)\n const padding = (4 - (parts[2]!.length % 4)) % 4\n const sigB64 = parts[2]!.replace(/-/g, '+').replace(/_/g, '/') + '='.repeat(padding)\n const sigBytes = Uint8Array.from(atob(sigB64), c => c.charCodeAt(0))\n\n const verifyAlg = alg.startsWith('ES')\n ? { name: 'ECDSA', hash: { name: `SHA-${alg.slice(2)}` } }\n : { name: 'RSASSA-PKCS1-v1_5' }\n\n const valid = await globalThis.crypto.subtle.verify(verifyAlg, cryptoKey, sigBytes, sigInput)\n if (!valid) throw new Error('ID token signature verification failed')\n\n const payload = JSON.parse(base64urlDecode(parts[1]!)) as OidcClaims\n const now = Math.floor(Date.now() / 1000)\n if (typeof payload['exp'] === 'number' && payload['exp'] < now) {\n throw new Error('ID token has expired')\n }\n\n return payload\n}\n\nexport function extractEmailFromClaims(claims: OidcClaims, mapping?: { email?: string }): string {\n const key = mapping?.email ?? 'email'\n const value = claims[key]\n if (typeof value !== 'string') throw new Error('OIDC token missing email claim')\n return value\n}\n\nexport function extractRolesFromClaims(\n claims: OidcClaims,\n mapping?: { roles?: string },\n): string[] {\n const key = mapping?.roles ?? 'consenti_roles'\n const value = claims[key]\n if (!Array.isArray(value)) return []\n return value.filter((v): v is string => typeof v === 'string')\n}\n\n// In-memory PKCE/state store. Replace with Redis or DB for multi-instance deployments.\nconst pendingStates = new Map<string, { verifier: string; nonce: string; expiresAt: number }>()\n\nsetInterval(() => {\n const now = Date.now()\n for (const [key, val] of pendingStates) {\n if (val.expiresAt < now) pendingStates.delete(key)\n }\n}, 5 * 60_000).unref()\n\nexport function storePkceState(state: string, verifier: string, nonce: string): void {\n pendingStates.set(state, { verifier, nonce, expiresAt: Date.now() + 10 * 60_000 })\n}\n\nexport function consumePkceState(\n state: string,\n): { verifier: string; nonce: string } | null {\n const entry = pendingStates.get(state)\n pendingStates.delete(state)\n if (!entry || entry.expiresAt < Date.now()) return null\n return { verifier: entry.verifier, nonce: entry.nonce }\n}\n","import type { SamlConfig } from '@consenti/types'\n\nfunction escXml(s: string): string {\n return s.replace(/&/g, '&').replace(/\"/g, '"').replace(/</g, '<').replace(/>/g, '>')\n}\n\nexport function buildSamlMetadataXml(config: SamlConfig): string {\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<EntityDescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\"\n entityID=\"saml:sp:consenti\">\n <SPSSODescriptor\n protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\"\n AuthnRequestsSigned=\"false\"\n WantAssertionsSigned=\"true\">\n <NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat>\n <AssertionConsumerService\n Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\"\n Location=\"${escXml(config.callbackUrl)}\"\n index=\"0\"\n isDefault=\"true\"/>\n </SPSSODescriptor>\n</EntityDescriptor>`\n}\n\nexport interface SamlUserInfo {\n email: string\n roles: string[]\n}\n\n// Validates a SAML response using the `samlify` peer dependency.\n// Install: npm install samlify\nexport async function validateSamlResponse(\n samlResponse: string,\n config: SamlConfig,\n): Promise<SamlUserInfo | null> {\n let samlify: {\n ServiceProvider: (cfg: Record<string, unknown>) => {\n parseLoginResponse: (\n idp: unknown,\n type: string,\n req: { body: Record<string, string> },\n ) => Promise<{ extract: { nameID: string; attributes: Record<string, unknown> } }>\n }\n IdentityProvider: (cfg: Record<string, unknown>) => unknown\n }\n\n try {\n // @ts-expect-error -- samlify is an optional peer dependency; callers must install it\n samlify = (await import('samlify')) as unknown as typeof samlify\n } catch {\n console.warn('[Consenti] samlify is not installed. Install it to use SAML auth mode.')\n return null\n }\n\n try {\n const sp = samlify.ServiceProvider({\n entityID: 'saml:sp:consenti',\n assertionConsumerService: [\n {\n Binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',\n Location: config.callbackUrl,\n },\n ],\n })\n const idp = samlify.IdentityProvider({\n entityID: config.issuer,\n singleSignOnService: [\n {\n Binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',\n Location: config.entryPoint,\n },\n ],\n signingCert: config.cert,\n })\n const result = await sp.parseLoginResponse(idp, 'post', {\n body: { SAMLResponse: samlResponse },\n })\n const email = result.extract.nameID\n const rolesAttr = result.extract.attributes['roles']\n const roles = Array.isArray(rolesAttr)\n ? rolesAttr.filter((r): r is string => typeof r === 'string')\n : []\n return { email, roles }\n } catch (err) {\n console.warn('[Consenti] SAML response validation failed:', err)\n return null\n }\n}\n","import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto'\n\nconst BASE32_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'\n\nfunction base32Encode(buf: Buffer): string {\n let result = ''\n let bits = 0\n let value = 0\n for (const byte of buf) {\n value = (value << 8) | byte\n bits += 8\n while (bits >= 5) {\n result += BASE32_CHARS[(value >>> (bits - 5)) & 0x1f]\n bits -= 5\n }\n }\n if (bits > 0) result += BASE32_CHARS[(value << (5 - bits)) & 0x1f]\n return result\n}\n\nfunction base32Decode(str: string): Buffer {\n const clean = str.toUpperCase().replace(/[^A-Z2-7]/g, '')\n const bytes: number[] = []\n let bits = 0\n let value = 0\n for (const char of clean) {\n const idx = BASE32_CHARS.indexOf(char)\n if (idx < 0) continue\n value = (value << 5) | idx\n bits += 5\n if (bits >= 8) {\n bytes.push((value >>> (bits - 8)) & 0xff)\n bits -= 8\n }\n }\n return Buffer.from(bytes)\n}\n\nfunction hotp(secret: Buffer, counter: number): string {\n const buf = Buffer.alloc(8)\n let c = counter\n for (let i = 7; i >= 0; i--) {\n buf[i] = c & 0xff\n c = Math.floor(c / 256)\n }\n const hmac = createHmac('sha1', secret).update(buf).digest()\n const offset = hmac[hmac.length - 1]! & 0x0f\n const code =\n ((hmac[offset]! & 0x7f) << 24) |\n ((hmac[offset + 1]! & 0xff) << 16) |\n ((hmac[offset + 2]! & 0xff) << 8) |\n (hmac[offset + 3]! & 0xff)\n return String(code % 1_000_000).padStart(6, '0')\n}\n\nexport function generateTotpSecret(): string {\n return base32Encode(randomBytes(20))\n}\n\nexport function generateTotp(secret: string, time = Date.now()): string {\n return hotp(base32Decode(secret), Math.floor(time / 30_000))\n}\n\nconst usedTokens = new Map<string, number>() // token → expiresAt\n\nsetInterval(() => {\n const now = Date.now()\n for (const [token, expiresAt] of usedTokens) {\n if (now >= expiresAt) usedTokens.delete(token)\n }\n}, 90_000).unref()\n\nexport function verifyTotp(secret: string, token: string, window = 1): boolean {\n if (usedTokens.has(token)) return false\n const counter = Math.floor(Date.now() / 30_000)\n const secretBuf = base32Decode(secret)\n const tokenBuf = Buffer.from(token)\n for (let i = -window; i <= window; i++) {\n const expected = Buffer.from(hotp(secretBuf, counter + i))\n if (expected.length === tokenBuf.length && timingSafeEqual(expected, tokenBuf)) {\n usedTokens.set(token, Date.now() + 90_000)\n return true\n }\n }\n return false\n}\n\nexport function totpQrUrl(secret: string, email: string, issuer = 'Consenti'): string {\n const label = encodeURIComponent(`${issuer}:${email}`)\n const params = new URLSearchParams({\n secret,\n issuer,\n algorithm: 'SHA1',\n digits: '6',\n period: '30',\n })\n return `otpauth://totp/${label}?${params.toString()}`\n}\n","/**\n * Single source of truth for all compliance groups, regulations, and country mappings.\n *\n * This is DATA, not types. The `Compliance` and `ComplianceGroupId` literal types\n * derived from the ID arrays below live in @consenti/types (packages/types/src/compliance.ts),\n * via a type-only import — that keeps @consenti/types free of runtime code.\n *\n * ─── HOW TO UPDATE ────────────────────────────────────────────────────────────\n *\n * ADD A NEW REGULATION:\n * 1. Add regulation ID string to `COMPLIANCE_REGULATION_IDS` below\n * (the `Compliance` type in @consenti/types auto-updates from it).\n * 2. Add it to the appropriate group's `compliances` array below.\n * 3. Add / update the country entry in `EMBEDDED_COMPLIANCE_MAP` below.\n * That is all — no other files need touching.\n *\n * ADD A NEW COMPLIANCE GROUP:\n * 1. Add the kebab-case ID to `COMPLIANCE_GROUP_IDS` below.\n * 2. Add a full group entry to `COMPLIANCE_GROUPS` below (label, compliances, flags).\n * 3. Add a validation rule set to `COMPLIANCE_VALIDATION_RULES` below.\n * 4. Map affected countries in `EMBEDDED_COMPLIANCE_MAP` to the new group.\n *\n * ADD OR UPDATE A COUNTRY:\n * Edit the entry in `EMBEDDED_COMPLIANCE_MAP.countries` below. That is the ONLY\n * place that needs changing for country-level jurisdiction updates.\n */\n\n// ─── Regulation IDs ───────────────────────────────────────────────────────────\n\nexport const COMPLIANCE_REGULATION_IDS = [\n // European Union\n 'gdpr', 'eprivacy',\n // United Kingdom\n 'uk-gdpr', 'pecr',\n // Switzerland\n 'revfadp',\n // Turkey\n 'kvkk',\n // North America — Canada\n 'pipeda', 'law25',\n // North America — US (California)\n 'ccpa', 'cpra',\n // North America — US state laws\n 'vcdpa', 'cpa-co', 'ctdpa', 'ucpa', 'icdpa-ia', 'icdpa-in', 'tipa',\n 'mcdpa-mt', 'mcdpa-mn', 'ocpa', 'tdpsa', 'dpdpa-de', 'njdpa', 'nhpa',\n 'ndpa-ne', 'modpa', 'kcdpa', 'ridtpa',\n // Latin America\n 'lgpd', 'lfpdppp', 'lpdp-ar', 'lpdp-pe', 'law1581-co', 'law18331-uy',\n 'law19628-cl', 'lopdp-ec', 'lpdp-cr', 'data-protection-pa', 'data-protection-do',\n // Asia — India\n 'dpdpa',\n // Asia — China\n 'pipl', 'dsl-cn', 'csl-cn',\n // Asia — Pacific\n 'appi', 'pipa-kr', 'pdpa-sg', 'pdpa-th', 'pdpa-my', 'dpa-ph', 'pdp-id',\n 'pdpd-vn', 'privacy-au', 'privacy-nz', 'pdpl-hk', 'pdpa-mo', 'pdpl-tw',\n 'privacy-bn', 'privacy-lk', 'privacy-np',\n // Middle East\n 'pdpl-sa', 'uae-pdpl', 'difc-dpl', 'adgm-dpr', 'qpdl-qa', 'pdpl-bh',\n 'pdpl-om', 'privacy-kw', 'privacy-il',\n // Africa\n 'popia', 'ndpa-ng', 'dpa-ke', 'dpa-gh', 'dpa-ug', 'dpa-rw', 'dpa-mu',\n 'dpa-bw', 'dpa-zm', 'dpa-zw', 'dpa-eg', 'dpa-ma', 'dpa-tn', 'dpa-dz',\n // Oceania\n 'privacy-fj', 'privacy-pg',\n] as const\n\n// ─── Compliance Group IDs ─────────────────────────────────────────────────────\n\nexport const COMPLIANCE_GROUP_IDS = [\n 'opt-in',\n 'opt-out',\n 'opt-out-strict',\n 'opt-in-dpdpa',\n 'opt-in-china',\n 'opt-in-brazil',\n 'general-privacy-consent',\n 'notice-only',\n] as const\n\n// Local alias for the shape checks below. The public `ComplianceGroupId` type\n// (derived from the same array) is re-exported from @consenti/types.\ntype ComplianceGroupId = typeof COMPLIANCE_GROUP_IDS[number]\n\n// ─── Compliance Groups ────────────────────────────────────────────────────────\n\nexport const COMPLIANCE_GROUPS = {\n 'opt-out-strict': {\n label: 'Opt-out Strict (CPRA / California)',\n description: 'California CPRA: opt-out with sale/sharing/sensitive categories required. GPC must be honored. Stricter than general US state laws.',\n compliances: ['cpra'],\n defaultGpc: 'honor',\n gpcAutoHonor: true,\n allowsLegitimateInterest: false,\n allowsTcf: false,\n requiresCpraCategory: true,\n requiresDpdpaDisclosure: false,\n },\n 'opt-out': {\n label: 'Opt-out (US State Laws)',\n description: 'US state privacy laws. Collect first, allow opt-out of sale/share. Covers CCPA and all state-level equivalents.',\n compliances: [\n 'ccpa',\n 'vcdpa', 'cpa-co', 'ctdpa', 'ucpa', 'icdpa-ia', 'icdpa-in', 'tipa',\n 'mcdpa-mt', 'mcdpa-mn', 'ocpa', 'tdpsa', 'dpdpa-de', 'njdpa', 'nhpa',\n 'ndpa-ne', 'modpa', 'kcdpa', 'ridtpa',\n ],\n defaultGpc: 'honor',\n gpcAutoHonor: true,\n allowsLegitimateInterest: false,\n allowsTcf: false,\n requiresCpraCategory: false,\n requiresDpdpaDisclosure: false,\n },\n 'notice-only': {\n label: 'Notice Only',\n description: 'A privacy notice is generally sufficient. No dedicated cookie banner law is encoded for this jurisdiction.',\n compliances: ['privacy-fj', 'privacy-pg'],\n defaultGpc: 'ignore',\n gpcAutoHonor: false,\n allowsLegitimateInterest: true,\n allowsTcf: false,\n requiresCpraCategory: false,\n requiresDpdpaDisclosure: false,\n },\n 'opt-in': {\n label: 'Standard Opt-in (GDPR)',\n description: 'GDPR / ePrivacy style: prior consent required before non-essential cookies. Granular consent, easy reject, easy withdrawal.',\n compliances: [\n 'gdpr', 'eprivacy', 'uk-gdpr', 'pecr', 'revfadp', 'kvkk', 'pdpa-th',\n 'pdpl-sa', 'uae-pdpl', 'difc-dpl', 'adgm-dpr', 'qpdl-qa', 'pdpl-bh', 'pdpl-om',\n 'law25',\n ],\n defaultGpc: 'ignore',\n gpcAutoHonor: false,\n allowsLegitimateInterest: true,\n allowsTcf: true,\n requiresCpraCategory: false,\n requiresDpdpaDisclosure: false,\n },\n 'opt-in-dpdpa': {\n label: 'Opt-in (India DPDPA)',\n description: \"India's Digital Personal Data Protection Act. Opt-in consent with data fiduciary disclosure. No legitimate interest basis.\",\n compliances: ['dpdpa'],\n defaultGpc: 'ignore',\n gpcAutoHonor: false,\n allowsLegitimateInterest: false,\n allowsTcf: false,\n requiresCpraCategory: false,\n requiresDpdpaDisclosure: true,\n },\n 'opt-in-china': {\n label: 'Opt-in (China PIPL / DSL)',\n description: 'China PIPL + DSL + CSL: strict opt-in with purpose specification, data minimisation, and cross-border transfer controls.',\n compliances: ['pipl', 'dsl-cn', 'csl-cn'],\n defaultGpc: 'ignore',\n gpcAutoHonor: false,\n allowsLegitimateInterest: false,\n allowsTcf: false,\n requiresCpraCategory: false,\n requiresDpdpaDisclosure: false,\n },\n 'opt-in-brazil': {\n label: 'Opt-in (Brazil LGPD)',\n description: 'Brazil LGPD: opt-in consent required. Legitimate interest is a valid basis. Analytics and advertising may differ in treatment.',\n compliances: ['lgpd'],\n defaultGpc: 'ignore',\n gpcAutoHonor: false,\n allowsLegitimateInterest: true,\n allowsTcf: false,\n requiresCpraCategory: false,\n requiresDpdpaDisclosure: false,\n },\n 'general-privacy-consent': {\n label: 'General Privacy Consent',\n description: 'Privacy notice or consent rules exist but the jurisdiction does not have a GDPR/PECR-style strict cookie banner law. Documenting legal basis is best practice.',\n compliances: [\n 'pipeda',\n 'popia', 'appi', 'pipa-kr',\n 'pdpa-sg', 'pdpa-my', 'dpa-ph', 'pdp-id', 'pdpd-vn',\n 'privacy-au', 'privacy-nz', 'pdpl-hk', 'pdpa-mo', 'pdpl-tw',\n 'privacy-bn', 'privacy-lk', 'privacy-np', 'privacy-kw', 'privacy-il',\n 'ndpa-ng', 'dpa-ke', 'dpa-gh', 'dpa-ug', 'dpa-rw', 'dpa-mu',\n 'dpa-bw', 'dpa-zm', 'dpa-zw', 'dpa-eg', 'dpa-ma', 'dpa-tn', 'dpa-dz',\n 'lfpdppp', 'lpdp-ar', 'lpdp-pe', 'law1581-co', 'law18331-uy',\n 'law19628-cl', 'lopdp-ec', 'lpdp-cr', 'data-protection-pa', 'data-protection-do',\n ],\n defaultGpc: 'ignore',\n gpcAutoHonor: false,\n allowsLegitimateInterest: true,\n allowsTcf: false,\n requiresCpraCategory: false,\n requiresDpdpaDisclosure: false,\n },\n} satisfies Record<ComplianceGroupId, {\n label: string\n description: string\n compliances: readonly string[]\n defaultGpc: 'ignore' | 'honor' | 'strict'\n gpcAutoHonor: boolean\n allowsLegitimateInterest: boolean\n allowsTcf: boolean\n requiresCpraCategory: boolean\n requiresDpdpaDisclosure: boolean\n}>\n\n// ─── GPC Options ──────────────────────────────────────────────────────────────\n\nexport const GPC_OPTIONS = [\n { value: 'ignore', label: 'Ignore', description: 'Do not check or respond to the GPC browser signal.' },\n { value: 'honor', label: 'Honor', description: 'Respect GPC as a valid opt-out signal. Show GPC variant banner once.' },\n { value: 'strict', label: 'Strict', description: 'Silently deny all non-mandatory cookies when GPC is detected. No banner shown.' },\n]\n\n// ─── Legal Basis Options ──────────────────────────────────────────────────────\n\nexport const LEGAL_BASIS_OPTIONS = [\n { value: 'mandatory', label: 'Strictly Necessary', description: 'Required for the service to function. No consent needed.' },\n { value: 'consent', label: 'Consent', description: 'Requires explicit user agreement. User can withdraw at any time.' },\n { value: 'legitimate_interest', label: 'Legitimate Interest', description: 'Based on legitimate business interest. User has the right to object.' },\n]\n\n// ─── CPRA Categories ──────────────────────────────────────────────────────────\n\nexport const CPRA_CATEGORIES = [\n { value: 'sale', label: 'Sale', description: 'Sale of personal data to third parties for their own use.' },\n { value: 'sharing', label: 'Sharing', description: 'Sharing for cross-context behavioral advertising (even without payment).' },\n { value: 'sensitive', label: 'Sensitive', description: 'Sensitive personal information (geolocation, health, race, biometrics, etc.). Requires opt-in even in California.' },\n]\n\n// ─── TCF Purposes (IAB TCF 2.2) ──────────────────────────────────────────────\n\nexport const TCF_PURPOSES = [\n { id: 1, name: 'Store and/or access information on a device', description: \"Cookies, device identifiers, or other information can be stored or accessed on your device.\" },\n { id: 2, name: 'Select basic ads', description: \"Ads can be shown based on the content you're viewing, the app you're using, or your approximate location.\" },\n { id: 3, name: 'Create a personalised ads profile', description: \"A profile can be built about you and your interests to show you personalised ads.\" },\n { id: 4, name: 'Select personalised ads', description: \"Personalised ads can be shown to you based on a profile about you.\" },\n { id: 5, name: 'Create a personalised content profile', description: \"A profile can be built about you and your interests to show you personalised content.\" },\n { id: 6, name: 'Select personalised content', description: \"Personalised content can be shown to you based on a profile about you.\" },\n { id: 7, name: 'Measure ad performance', description: \"The performance and effectiveness of ads that you see or interact with can be measured.\" },\n { id: 8, name: 'Measure content performance', description: \"The performance and effectiveness of content that you see or interact with can be measured.\" },\n { id: 9, name: 'Apply market research to generate audience insights', description: \"Market research can be used to learn more about the audiences who visit sites or use apps.\" },\n { id: 10, name: 'Develop and improve products', description: \"Your data can be used to improve existing systems and software, and to develop new products.\" },\n { id: 11, name: 'Use limited data to select content', description: \"Content can be selected based on limited data such as the website you are visiting.\" },\n]\n\nexport const TCF_SPECIAL_FEATURES = [\n { id: 1, name: 'Use precise geolocation data', description: \"Your precise location (within a radius of less than 500 metres) can be used.\" },\n { id: 2, name: 'Actively scan device characteristics for identification', description: \"Your device can be identified based on a scan of your device's unique combination of characteristics.\" },\n]\n\n// ─── Compliance Validation Rules ──────────────────────────────────────────────\n// check() returns true when a violation exists (i.e., the rule is broken)\n\nexport const COMPLIANCE_VALIDATION_RULES: Record<string, {\n errors: Array<{\n rule: string\n field: string\n check: (cookie: Record<string, unknown>) => boolean\n message: (cookieId: string) => string\n }>\n warnings: Array<{\n rule: string\n field: string\n check: (cookie: Record<string, unknown>) => boolean\n message: (cookieId: string) => string\n suggestion: string\n }>\n}> = {\n 'opt-in': {\n errors: [\n {\n rule: 'legal-basis-required',\n field: 'legalBasis',\n check: (c) => !c['legalBasis'],\n message: (id) => `Cookie \"${id}\" must have a legal basis set (Consent, Legitimate Interest, or Strictly Necessary) for GDPR compliance.`,\n },\n {\n rule: 'li-description-required',\n field: 'legitimateInterest.description',\n check: (c) => c['legalBasis'] === 'legitimate_interest' && !(c['legitimateInterest'] as Record<string, unknown> | undefined)?.['description'],\n message: (id) => `Cookie \"${id}\" uses Legitimate Interest but has no balancing test description. GDPR requires documenting your LI assessment.`,\n },\n ],\n warnings: [\n {\n rule: 'li-description-recommended',\n field: 'legitimateInterest.description',\n check: (c) => c['legalBasis'] === 'legitimate_interest' && !(c['legitimateInterest'] as Record<string, unknown> | undefined)?.['description'],\n message: (id) => `Cookie \"${id}\": adding a Legitimate Interest description improves transparency and is a GDPR best practice.`,\n suggestion: 'Add a brief description of your legitimate interest balancing test.',\n },\n ],\n },\n\n 'opt-out': {\n errors: [],\n warnings: [\n {\n rule: 'gpc-recommended',\n field: 'listenGpc',\n check: (c) => c['legalBasis'] !== 'mandatory' && !c['listenGpc'],\n message: (id) => `Cookie \"${id}\" does not listen for the GPC signal. US state privacy laws require honoring GPC for opt-out of sale/sharing.`,\n suggestion: 'Enable \"Listen for GPC signal\" on this cookie.',\n },\n ],\n },\n\n 'opt-out-strict': {\n errors: [\n {\n rule: 'cpra-category-required',\n field: 'cpraCategory',\n check: (c) => c['legalBasis'] !== 'mandatory' && !c['cpraCategory'],\n message: (id) => `Cookie \"${id}\" must have a CPRA category (Sale, Sharing, or Sensitive) assigned. Required under CPRA for all non-necessary cookies.`,\n },\n ],\n warnings: [\n {\n rule: 'gpc-strict-required',\n field: 'listenGpc',\n check: (c) => c['legalBasis'] !== 'mandatory' && !c['listenGpc'],\n message: (id) => `Cookie \"${id}\" does not listen for the GPC signal. Under CPRA, non-mandatory cookies must honor GPC as a Do Not Sell/Share signal.`,\n suggestion: 'Enable \"Listen for GPC signal\" on this cookie.',\n },\n ],\n },\n\n 'opt-in-dpdpa': {\n errors: [\n {\n rule: 'no-li-allowed',\n field: 'legalBasis',\n check: (c) => c['legalBasis'] === 'legitimate_interest',\n message: (id) => `Cookie \"${id}\" uses Legitimate Interest, which is not a valid legal basis under India's DPDPA. Use Consent or Strictly Necessary.`,\n },\n {\n rule: 'legal-basis-required',\n field: 'legalBasis',\n check: (c) => !c['legalBasis'],\n message: (id) => `Cookie \"${id}\" must have a legal basis set (Consent or Strictly Necessary) for DPDPA compliance.`,\n },\n ],\n warnings: [],\n },\n\n 'opt-in-china': {\n errors: [\n {\n rule: 'legal-basis-required',\n field: 'legalBasis',\n check: (c) => !c['legalBasis'],\n message: (id) => `Cookie \"${id}\" must have a legal basis set for China PIPL compliance. Consent is the primary valid basis.`,\n },\n ],\n warnings: [\n {\n rule: 'li-limited-under-pipl',\n field: 'legalBasis',\n check: (c) => c['legalBasis'] === 'legitimate_interest',\n message: (id) => `Cookie \"${id}\" uses Legitimate Interest. Under China's PIPL, LI is narrowly scoped and data processing purposes must be strictly documented.`,\n suggestion: 'Consider using Consent for this cookie to ensure PIPL compliance. Document the specific legitimate interest basis if retaining LI.',\n },\n ],\n },\n\n 'opt-in-brazil': {\n errors: [\n {\n rule: 'legal-basis-required',\n field: 'legalBasis',\n check: (c) => !c['legalBasis'],\n message: (id) => `Cookie \"${id}\" must have a legal basis set. Brazil's LGPD requires one of ten legal bases; Consent or Legitimate Interest are most common for cookies.`,\n },\n ],\n warnings: [\n {\n rule: 'li-description-recommended',\n field: 'legitimateInterest.description',\n check: (c) => c['legalBasis'] === 'legitimate_interest' && !(c['legitimateInterest'] as Record<string, unknown> | undefined)?.['description'],\n message: (id) => `Cookie \"${id}\" uses Legitimate Interest. LGPD requires documenting the basis and conducting an impact assessment.`,\n suggestion: 'Add a Legitimate Interest description to document the LGPD basis and your impact assessment.',\n },\n ],\n },\n\n 'general-privacy-consent': {\n errors: [],\n warnings: [\n {\n rule: 'legal-basis-recommended',\n field: 'legalBasis',\n check: (c) => !c['legalBasis'],\n message: (id) => `Cookie \"${id}\" has no legal basis documented. While a strict cookie banner may not be legally required in this jurisdiction, documenting legal basis is a privacy best practice.`,\n suggestion: 'Set a legal basis to improve compliance documentation and future-proof against stricter enforcement.',\n },\n ],\n },\n\n 'notice-only': {\n errors: [],\n warnings: [],\n },\n}\n\n// ─── Embedded Jurisdiction → Compliance Group Map ─────────────────────────────\n// Version tag: update when regulations or mappings change materially.\n// HOW TO UPDATE: edit or add a country entry below. That is the ONLY file change needed.\n//\n// locales: BCP 47 tags for the most commonly used web/IT locales in that country.\n// Only well-supported, widely-used locales are listed. English-speaking countries\n// use 'en' (no country suffix). No country-specific English variants (en-XX) anywhere.\n\nexport const EMBEDDED_COMPLIANCE_MAP = {\n version: '2026-07',\n countries: {\n // ─── Europe — EU 27 ───────────────────────────────────────────────────────\n AT: { name: 'Austria', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Austria (GDPR)', locales: ['de-AT'] },\n BE: { name: 'Belgium', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Belgium (GDPR)', locales: ['nl-BE', 'fr-BE'] },\n BG: { name: 'Bulgaria', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Bulgaria (GDPR)', locales: ['bg-BG'] },\n HR: { name: 'Croatia', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Croatia (GDPR)', locales: ['hr-HR'] },\n CY: { name: 'Cyprus', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Cyprus (GDPR)', locales: ['el-CY'] },\n CZ: { name: 'Czechia', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Czechia (GDPR)', locales: ['cs-CZ'] },\n DK: { name: 'Denmark', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Denmark (GDPR)', locales: ['da-DK'] },\n EE: { name: 'Estonia', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Estonia (GDPR)', locales: ['et-EE'] },\n FI: { name: 'Finland', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Finland (GDPR)', locales: ['fi-FI'] },\n FR: { name: 'France', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'France (GDPR)', locales: ['fr-FR'] },\n DE: { name: 'Germany', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Germany (GDPR)', locales: ['de-DE'] },\n GR: { name: 'Greece', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Greece (GDPR)', locales: ['el-GR'] },\n HU: { name: 'Hungary', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Hungary (GDPR)', locales: ['hu-HU'] },\n IE: { name: 'Ireland', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Ireland (GDPR)', locales: ['en'] },\n IT: { name: 'Italy', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Italy (GDPR)', locales: ['it-IT'] },\n LV: { name: 'Latvia', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Latvia (GDPR)', locales: ['lv-LV'] },\n LT: { name: 'Lithuania', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Lithuania (GDPR)', locales: ['lt-LT'] },\n LU: { name: 'Luxembourg', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Luxembourg (GDPR)', locales: ['fr-LU', 'de-LU'] },\n MT: { name: 'Malta', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Malta (GDPR)', locales: ['mt-MT', 'en'] },\n NL: { name: 'Netherlands', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Netherlands (GDPR)', locales: ['nl-NL'] },\n PL: { name: 'Poland', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Poland (GDPR)', locales: ['pl-PL'] },\n PT: { name: 'Portugal', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Portugal (GDPR)', locales: ['pt-PT'] },\n RO: { name: 'Romania', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Romania (GDPR)', locales: ['ro-RO'] },\n SK: { name: 'Slovakia', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Slovakia (GDPR)', locales: ['sk-SK'] },\n SI: { name: 'Slovenia', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Slovenia (GDPR)', locales: ['sl-SI'] },\n ES: { name: 'Spain', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Spain (GDPR)', locales: ['es-ES'] },\n SE: { name: 'Sweden', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Sweden (GDPR)', locales: ['sv-SE'] },\n // ─── Europe — EEA non-EU ──────────────────────────────────────────────────\n IS: { name: 'Iceland', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Iceland (GDPR via EEA)', locales: ['is-IS'] },\n LI: { name: 'Liechtenstein', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Liechtenstein (GDPR via EEA)', locales: ['de-LI'] },\n NO: { name: 'Norway', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Norway (GDPR via EEA)', locales: ['nb-NO'] },\n // ─── Europe — GDPR-aligned candidate/observer countries ──────────────────\n AD: { name: 'Andorra', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Andorra (GDPR-aligned)', locales: ['ca-AD'] },\n AL: { name: 'Albania', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Albania (GDPR-aligned)', locales: ['sq-AL'] },\n BA: { name: 'Bosnia and Herzegovina', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Bosnia and Herzegovina (GDPR-aligned)', locales: ['bs-BA', 'sr-Latn-BA'] },\n GG: { name: 'Guernsey', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Guernsey (DPA based on GDPR)', locales: ['en'] },\n GI: { name: 'Gibraltar', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Gibraltar (DPA based on UK GDPR)', locales: ['en'] },\n GL: { name: 'Greenland', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Greenland (Danish GDPR implementation)', locales: ['da-GL'] },\n MC: { name: 'Monaco', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Monaco (GDPR-aligned)', locales: ['fr-MC'] },\n ME: { name: 'Montenegro', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Montenegro (GDPR-aligned)', locales: ['sr-Latn-ME'] },\n MK: { name: 'North Macedonia', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'North Macedonia (GDPR-aligned)', locales: ['mk-MK'] },\n RS: { name: 'Serbia', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Serbia (GDPR-aligned)', locales: ['sr-RS'] },\n SM: { name: 'San Marino', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'San Marino (GDPR-aligned)', locales: ['it-SM'] },\n TR: { name: 'Türkiye', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Türkiye (KVKK)', locales: ['tr-TR'] },\n // ─── North America ────────────────────────────────────────────────────────\n CA: {\n name: 'Canada',\n type: 'country',\n complianceGroup: 'general-privacy-consent',\n default: 'general-privacy-consent',\n description: 'Canada (PIPEDA / Law 25)',\n locales: ['en', 'fr-CA'],\n overriddenRegions: {\n QC: { name: 'Quebec', type: 'region', complianceGroup: 'opt-in', description: 'Quebec — Law 25 (GDPR-style opt-in)' },\n },\n },\n US: {\n name: 'United States',\n type: 'country',\n // complianceGroup: base when state known but has no specific law\n // default: used when state CANNOT be detected (use most strict = opt-out-strict)\n complianceGroup: 'opt-out',\n default: 'opt-out-strict',\n description: 'United States — opt-out-strict (CPRA) used when state cannot be detected',\n locales: ['en', 'es-US'],\n overriddenRegions: {\n CA: { name: 'California', type: 'region', complianceGroup: 'opt-out-strict', description: 'California — CPRA/CCPA' },\n VA: { name: 'Virginia', type: 'region', complianceGroup: 'opt-out', description: 'Virginia — VCDPA' },\n CO: { name: 'Colorado', type: 'region', complianceGroup: 'opt-out', description: 'Colorado — CPA' },\n CT: { name: 'Connecticut', type: 'region', complianceGroup: 'opt-out', description: 'Connecticut — CTDPA' },\n UT: { name: 'Utah', type: 'region', complianceGroup: 'opt-out', description: 'Utah — UCPA' },\n TX: { name: 'Texas', type: 'region', complianceGroup: 'opt-out', description: 'Texas — TDPSA' },\n DE: { name: 'Delaware', type: 'region', complianceGroup: 'opt-out', description: 'Delaware — DPDPA' },\n NJ: { name: 'New Jersey', type: 'region', complianceGroup: 'opt-out', description: 'New Jersey — NJDPA' },\n OR: { name: 'Oregon', type: 'region', complianceGroup: 'opt-out', description: 'Oregon — OCPA' },\n MN: { name: 'Minnesota', type: 'region', complianceGroup: 'opt-out', description: 'Minnesota — MCDPA' },\n MD: { name: 'Maryland', type: 'region', complianceGroup: 'opt-out', description: 'Maryland — MODPA' },\n KY: { name: 'Kentucky', type: 'region', complianceGroup: 'opt-out', description: 'Kentucky — KCDPA' },\n TN: { name: 'Tennessee', type: 'region', complianceGroup: 'opt-out', description: 'Tennessee — TIPA' },\n NE: { name: 'Nebraska', type: 'region', complianceGroup: 'opt-out', description: 'Nebraska — NDPA' },\n IA: { name: 'Iowa', type: 'region', complianceGroup: 'opt-out', description: 'Iowa — ICDPA' },\n IN: { name: 'Indiana', type: 'region', complianceGroup: 'opt-out', description: 'Indiana — ICDPA' },\n MT: { name: 'Montana', type: 'region', complianceGroup: 'opt-out', description: 'Montana — MCDPA' },\n NH: { name: 'New Hampshire', type: 'region', complianceGroup: 'opt-out', description: 'New Hampshire — NHPA' },\n RI: { name: 'Rhode Island', type: 'region', complianceGroup: 'opt-out', description: 'Rhode Island — RIDTPA' },\n },\n },\n // ─── Latin America ────────────────────────────────────────────────────────\n AR: { name: 'Argentina', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Argentina (LPDP)', locales: ['es-AR'] },\n BO: { name: 'Bolivia', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Bolivia', locales: ['es-BO'] },\n BR: { name: 'Brazil', type: 'country', complianceGroup: 'opt-in-brazil', default: 'opt-in-brazil', description: 'Brazil (LGPD)', locales: ['pt-BR'] },\n CL: { name: 'Chile', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Chile (Law 19.628)', locales: ['es-CL'] },\n CO: { name: 'Colombia', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Colombia (Law 1581)', locales: ['es-CO'] },\n CR: { name: 'Costa Rica', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Costa Rica (LPDP)', locales: ['es-CR'] },\n DO: { name: 'Dominican Republic', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Dominican Republic', locales: ['es-DO'] },\n EC: { name: 'Ecuador', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Ecuador (LOPDP)', locales: ['es-EC'] },\n GF: { name: 'French Guiana', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'French Guiana', locales: ['fr-GF'] },\n GT: { name: 'Guatemala', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Guatemala', locales: ['es-GT'] },\n GY: { name: 'Guyana', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Guyana', locales: ['en'] },\n HN: { name: 'Honduras', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Honduras', locales: ['es-HN'] },\n HT: { name: 'Haiti', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Haiti', locales: ['fr-HT'] },\n JM: { name: 'Jamaica', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Jamaica', locales: ['en'] },\n MX: { name: 'Mexico', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Mexico (LFPDPPP)', locales: ['es-MX'] },\n NI: { name: 'Nicaragua', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Nicaragua', locales: ['es-NI'] },\n PA: { name: 'Panama', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Panama', locales: ['es-PA'] },\n PE: { name: 'Peru', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Peru (LPDP)', locales: ['es-PE'] },\n PY: { name: 'Paraguay', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Paraguay', locales: ['es-PY'] },\n SR: { name: 'Suriname', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Suriname', locales: ['nl-SR'] },\n SV: { name: 'El Salvador', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'El Salvador', locales: ['es-SV'] },\n TT: { name: 'Trinidad and Tobago', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Trinidad and Tobago', locales: ['en'] },\n UY: { name: 'Uruguay', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Uruguay (Law 18.331)', locales: ['es-UY'] },\n VE: { name: 'Venezuela', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Venezuela', locales: ['es-VE'] },\n // ─── Caribbean ────────────────────────────────────────────────────────────\n AG: { name: 'Antigua and Barbuda', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Antigua and Barbuda', locales: ['en'] },\n BB: { name: 'Barbados', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Barbados', locales: ['en'] },\n BL: { name: 'Saint Barthélemy', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Saint Barthélemy', locales: ['fr-BL'] },\n BM: { name: 'Bermuda', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Bermuda', locales: ['en'] },\n BS: { name: 'Bahamas', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Bahamas', locales: ['en'] },\n CU: { name: 'Cuba', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Cuba', locales: ['es-CU'] },\n DM: { name: 'Dominica', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Dominica', locales: ['en'] },\n GD: { name: 'Grenada', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Grenada', locales: ['en'] },\n KN: { name: 'Saint Kitts and Nevis', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Saint Kitts and Nevis', locales: ['en'] },\n LC: { name: 'Saint Lucia', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Saint Lucia', locales: ['en'] },\n PM: { name: 'Saint Pierre and Miquelon', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Saint Pierre and Miquelon', locales: ['fr-PM'] },\n PR: { name: 'Puerto Rico', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Puerto Rico', locales: ['es-PR', 'en'] },\n VC: { name: 'Saint Vincent and the Grenadines', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Saint Vincent and the Grenadines', locales: ['en'] },\n // ─── Asia — India ─────────────────────────────────────────────────────────\n IN: { name: 'India', type: 'country', complianceGroup: 'opt-in-dpdpa', default: 'opt-in-dpdpa', description: 'India (DPDPA)', locales: ['hi-IN', 'en', 'bn-IN', 'ta-IN'] },\n // ─── Asia — China ─────────────────────────────────────────────────────────\n CN: { name: 'China', type: 'country', complianceGroup: 'opt-in-china', default: 'opt-in-china', description: 'China (PIPL + DSL + CSL)', locales: ['zh-CN'] },\n // ─── Asia — Southeast Asia ────────────────────────────────────────────────\n BN: { name: 'Brunei', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Brunei (Personal Data Protection Order)', locales: ['ms-BN', 'en'] },\n ID: { name: 'Indonesia', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Indonesia (PDP Law)', locales: ['id-ID'] },\n KH: { name: 'Cambodia', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Cambodia', locales: ['km-KH'] },\n LA: { name: 'Laos', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Laos', locales: ['lo-LA'] },\n MM: { name: 'Myanmar', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Myanmar', locales: ['my-MM'] },\n MY: { name: 'Malaysia', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Malaysia (PDPA)', locales: ['ms-MY', 'zh-MY', 'en'] },\n PH: { name: 'Philippines', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Philippines (DPA)', locales: ['fil-PH', 'en'] },\n SG: { name: 'Singapore', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Singapore (PDPA)', locales: ['zh-SG', 'ms-SG', 'ta-SG', 'en'] },\n TH: { name: 'Thailand', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Thailand (PDPA — GDPR-style opt-in)', locales: ['th-TH'] },\n TL: { name: 'Timor-Leste', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Timor-Leste', locales: ['pt-TL'] },\n VN: { name: 'Vietnam', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Vietnam (PDPD)', locales: ['vi-VN'] },\n // ─── Asia — East Asia ─────────────────────────────────────────────────────\n HK: { name: 'Hong Kong', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Hong Kong SAR (PDPO)', locales: ['zh-HK'] },\n JP: { name: 'Japan', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Japan (APPI)', locales: ['ja-JP'] },\n KP: { name: 'North Korea', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'North Korea', locales: ['ko-KP'] },\n KR: { name: 'South Korea', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'South Korea (PIPA)', locales: ['ko-KR'] },\n MN: { name: 'Mongolia', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Mongolia', locales: ['mn-MN'] },\n MO: { name: 'Macau', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Macau SAR (PDPA)', locales: ['zh-MO', 'pt-MO'] },\n TW: { name: 'Taiwan', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Taiwan (PDPL)', locales: ['zh-TW'] },\n // ─── Asia — South Asia ────────────────────────────────────────────────────\n AF: { name: 'Afghanistan', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Afghanistan', locales: ['fa-AF'] },\n BD: { name: 'Bangladesh', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Bangladesh', locales: ['bn-BD'] },\n BT: { name: 'Bhutan', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Bhutan', locales: ['dz-BT'] },\n IO: { name: 'British Indian Ocean Territory', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'British Indian Ocean Territory', locales: ['en'] },\n LK: { name: 'Sri Lanka', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Sri Lanka', locales: ['si-LK', 'ta-LK'] },\n MV: { name: 'Maldives', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Maldives', locales: ['dv-MV'] },\n NP: { name: 'Nepal', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Nepal', locales: ['ne-NP'] },\n PK: { name: 'Pakistan', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Pakistan', locales: ['ur-PK', 'en'] },\n // ─── Asia — Central Asia ──────────────────────────────────────────────────\n AM: { name: 'Armenia', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Armenia', locales: ['hy-AM'] },\n AZ: { name: 'Azerbaijan', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Azerbaijan', locales: ['az-AZ'] },\n GE: { name: 'Georgia', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Georgia', locales: ['ka-GE'] },\n KG: { name: 'Kyrgyzstan', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Kyrgyzstan', locales: ['ky-KG', 'ru-KG'] },\n KZ: { name: 'Kazakhstan', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Kazakhstan', locales: ['kk-KZ', 'ru-KZ'] },\n TJ: { name: 'Tajikistan', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Tajikistan', locales: ['tg-TJ'] },\n TM: { name: 'Turkmenistan', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Turkmenistan', locales: ['tk-TM'] },\n UZ: { name: 'Uzbekistan', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Uzbekistan', locales: ['uz-UZ'] },\n // ─── Middle East ──────────────────────────────────────────────────────────\n AE: { name: 'United Arab Emirates', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'United Arab Emirates (UAE PDPL / DIFC DPL / ADGM DPR)', locales: ['ar-AE'] },\n BH: { name: 'Bahrain', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Bahrain (PDPL)', locales: ['ar-BH'] },\n IL: { name: 'Israel', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Israel (Privacy Protection Law)', locales: ['he-IL', 'ar-IL'] },\n IQ: { name: 'Iraq', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Iraq', locales: ['ar-IQ'] },\n IR: { name: 'Iran', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Iran', locales: ['fa-IR'] },\n JO: { name: 'Jordan', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Jordan', locales: ['ar-JO'] },\n KW: { name: 'Kuwait', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Kuwait', locales: ['ar-KW'] },\n LB: { name: 'Lebanon', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Lebanon', locales: ['ar-LB'] },\n OM: { name: 'Oman', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Oman (PDPL)', locales: ['ar-OM'] },\n PS: { name: 'Palestine', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Palestine', locales: ['ar-PS'] },\n QA: { name: 'Qatar', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Qatar (PDPL)', locales: ['ar-QA'] },\n SA: { name: 'Saudi Arabia', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Saudi Arabia (PDPL)', locales: ['ar-SA'] },\n SY: { name: 'Syria', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Syria', locales: ['ar-SY'] },\n YE: { name: 'Yemen', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Yemen', locales: ['ar-YE'] },\n // ─── Africa — West ────────────────────────────────────────────────────────\n BF: { name: 'Burkina Faso', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Burkina Faso', locales: ['fr-BF'] },\n BJ: { name: 'Benin', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Benin', locales: ['fr-BJ'] },\n CI: { name: \"Côte d'Ivoire\", type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: \"Côte d'Ivoire\", locales: ['fr-CI'] },\n CM: { name: 'Cameroon', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Cameroon', locales: ['fr-CM', 'en'] },\n CV: { name: 'Cabo Verde', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Cabo Verde', locales: ['pt-CV'] },\n GA: { name: 'Gabon', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Gabon', locales: ['fr-GA'] },\n GH: { name: 'Ghana', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Ghana (DPA)', locales: ['en'] },\n GM: { name: 'Gambia', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Gambia', locales: ['en'] },\n GN: { name: 'Guinea', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Guinea', locales: ['fr-GN'] },\n GQ: { name: 'Equatorial Guinea', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Equatorial Guinea', locales: ['es-GQ', 'fr-GQ'] },\n GW: { name: 'Guinea-Bissau', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Guinea-Bissau', locales: ['pt-GW'] },\n LR: { name: 'Liberia', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Liberia', locales: ['en'] },\n ML: { name: 'Mali', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Mali', locales: ['fr-ML'] },\n MR: { name: 'Mauritania', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Mauritania', locales: ['ar-MR'] },\n NE: { name: 'Niger', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Niger', locales: ['fr-NE'] },\n NG: { name: 'Nigeria', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Nigeria (NDPA)', locales: ['en'] },\n SL: { name: 'Sierra Leone', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Sierra Leone', locales: ['en'] },\n SN: { name: 'Senegal', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Senegal', locales: ['fr-SN'] },\n TG: { name: 'Togo', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Togo', locales: ['fr-TG'] },\n // ─── Africa — East ────────────────────────────────────────────────────────\n BI: { name: 'Burundi', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Burundi', locales: ['fr-BI'] },\n DJ: { name: 'Djibouti', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Djibouti', locales: ['fr-DJ', 'ar-DJ'] },\n ER: { name: 'Eritrea', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Eritrea', locales: ['ti-ER'] },\n ET: { name: 'Ethiopia', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Ethiopia', locales: ['am-ET'] },\n KE: { name: 'Kenya', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Kenya (DPA)', locales: ['sw-KE', 'en'] },\n KM: { name: 'Comoros', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Comoros', locales: ['ar-KM', 'fr-KM'] },\n MG: { name: 'Madagascar', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Madagascar', locales: ['fr-MG'] },\n MU: { name: 'Mauritius', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Mauritius (DPA)', locales: ['en', 'fr-MU'] },\n MW: { name: 'Malawi', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Malawi', locales: ['en'] },\n MZ: { name: 'Mozambique', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Mozambique', locales: ['pt-MZ'] },\n RW: { name: 'Rwanda', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Rwanda (DPA)', locales: ['rw-RW', 'en'] },\n SC: { name: 'Seychelles', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Seychelles', locales: ['fr-SC', 'en'] },\n SO: { name: 'Somalia', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Somalia', locales: ['so-SO'] },\n SS: { name: 'South Sudan', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'South Sudan', locales: ['en'] },\n ST: { name: 'São Tomé and Príncipe', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'São Tomé and Príncipe', locales: ['pt-ST'] },\n TZ: { name: 'Tanzania', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Tanzania', locales: ['sw-TZ', 'en'] },\n UG: { name: 'Uganda', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Uganda (DPA)', locales: ['en'] },\n // ─── Africa — Southern ────────────────────────────────────────────────────\n AO: { name: 'Angola', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Angola', locales: ['pt-AO'] },\n BW: { name: 'Botswana', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Botswana (DPA)', locales: ['en'] },\n LS: { name: 'Lesotho', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Lesotho', locales: ['en'] },\n NA: { name: 'Namibia', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Namibia', locales: ['en'] },\n SZ: { name: 'Eswatini', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Eswatini', locales: ['en'] },\n ZA: { name: 'South Africa', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'South Africa (POPIA)', locales: ['en', 'af-ZA'] },\n ZM: { name: 'Zambia', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Zambia (DPA)', locales: ['en'] },\n ZW: { name: 'Zimbabwe', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Zimbabwe (DPA)', locales: ['en'] },\n // ─── Africa — North ───────────────────────────────────────────────────────\n DZ: { name: 'Algeria', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Algeria', locales: ['ar-DZ', 'fr-DZ'] },\n EG: { name: 'Egypt', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Egypt (DPA)', locales: ['ar-EG'] },\n LY: { name: 'Libya', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Libya', locales: ['ar-LY'] },\n MA: { name: 'Morocco', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Morocco', locales: ['ar-MA', 'fr-MA'] },\n SD: { name: 'Sudan', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Sudan', locales: ['ar-SD'] },\n TN: { name: 'Tunisia', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Tunisia (DPA)', locales: ['ar-TN', 'fr-TN'] },\n // ─── Africa — Central ─────────────────────────────────────────────────────\n CD: { name: 'DR Congo', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'DR Congo', locales: ['fr-CD'] },\n CF: { name: 'Central African Republic', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Central African Republic', locales: ['fr-CF'] },\n CG: { name: 'Republic of Congo', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Republic of Congo', locales: ['fr-CG'] },\n TD: { name: 'Chad', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Chad', locales: ['fr-TD', 'ar-TD'] },\n // ─── Europe — Eastern ─────────────────────────────────────────────────────\n BY: { name: 'Belarus', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Belarus', locales: ['be-BY', 'ru-BY'] },\n MD: { name: 'Moldova', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Moldova', locales: ['ro-MD'] },\n RU: { name: 'Russia', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Russia', locales: ['ru-RU'] },\n UA: { name: 'Ukraine', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Ukraine', locales: ['uk-UA'] },\n VA: { name: 'Holy See', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Holy See', locales: ['it-VA'] },\n // ─── Oceania ──────────────────────────────────────────────────────────────\n AU: { name: 'Australia', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'Australia (Privacy Act)', locales: ['en'] },\n FJ: { name: 'Fiji', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Fiji', locales: ['en'] },\n FM: { name: 'Micronesia', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Micronesia', locales: ['en'] },\n KI: { name: 'Kiribati', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Kiribati', locales: ['en'] },\n MH: { name: 'Marshall Islands', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Marshall Islands', locales: ['en'] },\n MP: { name: 'Northern Mariana Islands', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Northern Mariana Islands', locales: ['en'] },\n NC: { name: 'New Caledonia', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'New Caledonia', locales: ['fr-NC'] },\n NF: { name: 'Norfolk Island', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Norfolk Island', locales: ['en'] },\n NR: { name: 'Nauru', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Nauru', locales: ['en'] },\n NU: { name: 'Niue', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Niue', locales: ['en'] },\n NZ: { name: 'New Zealand', type: 'country', complianceGroup: 'general-privacy-consent', default: 'general-privacy-consent', description: 'New Zealand (Privacy Act)', locales: ['en'] },\n PF: { name: 'French Polynesia', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'French Polynesia', locales: ['fr-PF'] },\n PG: { name: 'Papua New Guinea', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Papua New Guinea', locales: ['en'] },\n PW: { name: 'Palau', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Palau', locales: ['en'] },\n SB: { name: 'Solomon Islands', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Solomon Islands', locales: ['en'] },\n TO: { name: 'Tonga', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Tonga', locales: ['en'] },\n TV: { name: 'Tuvalu', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Tuvalu', locales: ['en'] },\n VU: { name: 'Vanuatu', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Vanuatu', locales: ['fr-VU', 'en'] },\n WS: { name: 'Samoa', type: 'country', complianceGroup: 'notice-only', default: 'notice-only', description: 'Samoa', locales: ['en'] },\n // ─── Europe — GDPR-equivalent / adequacy ─────────────────────────────────\n UK: { name: 'United Kingdom', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'United Kingdom (UK GDPR + PECR)', locales: ['en'] },\n CH: { name: 'Switzerland', type: 'country', complianceGroup: 'opt-in', default: 'opt-in', description: 'Switzerland (revFADP)', locales: ['de-CH', 'fr-CH', 'it-CH'] },\n },\n} satisfies {\n version: string\n countries: Record<string, {\n name: string\n type: 'country'\n complianceGroup: ComplianceGroupId\n default: ComplianceGroupId\n description: string\n locales: readonly string[]\n overriddenRegions?: Record<string, {\n name: string\n type: 'region'\n complianceGroup: ComplianceGroupId\n description: string\n }>\n }>\n}\n\nexport const COUNTRY_CODES = Object.entries(EMBEDDED_COMPLIANCE_MAP.countries).reduce(function (acc, [c, d]) {\n acc[c] = d.name;\n return acc;\n}, {} as Record<string, string>);\n\nexport const LOCALES = Object.values(EMBEDDED_COMPLIANCE_MAP.countries).reduce(function (acc, c) {\n c.locales.forEach(l => {\n acc[l] = c.name;\n })\n return acc;\n}, {} as Record<string, string>);\n","import type { CreateProfileInput, UpdateProfileInput, ProfileConfig } from '@consenti/types'\n\nexport interface ValidationResult {\n valid: boolean\n error?: string\n}\n\nexport function validateCreateProfile(body: unknown): ValidationResult {\n if (!body || typeof body !== 'object') return { valid: false, error: 'Request body must be a JSON object' }\n const b = body as Record<string, unknown>\n if (typeof b['name'] !== 'string' || !b['name']) return { valid: false, error: 'name is required' }\n if (typeof b['defaultLocale'] !== 'string' || !b['defaultLocale']) return { valid: false, error: 'defaultLocale is required' }\n if (!b['profileJson'] || typeof b['profileJson'] !== 'object') return { valid: false, error: 'profileJson is required' }\n const pj = b['profileJson'] as Record<string, unknown>\n if (typeof pj['cookieTemplateId'] !== 'string' || !pj['cookieTemplateId']) {\n return { valid: false, error: 'profileJson.cookieTemplateId is required' }\n }\n if (typeof pj['uiTemplateId'] !== 'string' || !pj['uiTemplateId']) {\n return { valid: false, error: 'profileJson.uiTemplateId is required' }\n }\n return { valid: true }\n}\n\nexport function validateUpdateProfile(body: unknown): ValidationResult {\n if (!body || typeof body !== 'object') return { valid: false, error: 'Request body must be a JSON object' }\n return { valid: true }\n}\n\nexport function castCreateProfile(body: Record<string, unknown>, tenantId: string): CreateProfileInput {\n return {\n tenantId,\n name: body['name'] as string,\n defaultLocale: body['defaultLocale'] as string,\n profileJson: body['profileJson'] as CreateProfileInput['profileJson'],\n }\n}\n\nexport function castUpdateProfile(body: Record<string, unknown>): UpdateProfileInput {\n const result: UpdateProfileInput = {}\n if (typeof body['name'] === 'string') result.name = body['name']\n if (typeof body['defaultLocale'] === 'string') result.defaultLocale = body['defaultLocale']\n if (body['profileJson'] != null) result.profileJson = body['profileJson'] as ProfileConfig\n return result\n}\n","import type { Cookie, ComplianceValidationResult, ComplianceViolation, ComplianceWarningItem } from '@consenti/types'\nimport { COMPLIANCE_VALIDATION_RULES } from '@consenti/utils'\n\nexport function validateProfileCompliance(\n cookies: Cookie[],\n complianceGroup: string,\n): ComplianceValidationResult {\n const rules = COMPLIANCE_VALIDATION_RULES[complianceGroup]\n if (!rules) return { valid: true, errors: [], warnings: [] }\n\n const errors: ComplianceViolation[] = []\n const warnings: ComplianceWarningItem[] = []\n\n for (const cookie of cookies) {\n const c = cookie as unknown as Record<string, unknown>\n\n for (const rule of rules.errors) {\n if (rule.check(c)) {\n errors.push({\n cookieId: cookie.id,\n field: rule.field,\n message: rule.message(cookie.id),\n rule: rule.rule,\n })\n }\n }\n\n for (const rule of rules.warnings) {\n if (rule.check(c)) {\n warnings.push({\n cookieId: cookie.id,\n field: rule.field,\n message: rule.message(cookie.id),\n suggestion: rule.suggestion,\n })\n }\n }\n }\n\n return { valid: errors.length === 0, errors, warnings }\n}\n","import type { StorageAdapter, AuthConfig, Cookie } from '@consenti/types'\nimport { COMPLIANCE_GROUPS } from '@consenti/utils'\nimport { json, parseJsonBody } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\nimport { validateCreateProfile, validateUpdateProfile, castCreateProfile, castUpdateProfile } from '../../validators/profile.validator'\nimport type { ProfileService } from '../../services/profile.service'\nimport { validateProfileCompliance } from '../../services/compliance-validator.service'\n\nexport function buildAdminProfileRoutes(\n service: ProfileService,\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request, perm?: string) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { user, denied: authError(user, perm) }\n }\n\n function tenantAllowed(user: { allowedTenants: string[] } | null, tenantId: string): boolean {\n if (!user) return false\n return user.allowedTenants.length === 0 || user.allowedTenants.includes(tenantId)\n }\n\n return {\n 'GET /profiles': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user, denied } = await auth(req, 'profile:view')\n if (denied) return denied\n if (!tenantAllowed(user, 'default')) return json(200, [])\n const url = new URL(req.url)\n if (url.searchParams.get('summary') === '1') {\n return json(200, await service.listSummary())\n }\n return json(200, await service.list())\n }),\n\n 'GET /profiles/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:view')\n if (denied) return denied\n const profile = await service.get(p['id'] ?? '')\n if (!profile) return errorResponse(404, 'Profile not found')\n return json(200, profile)\n }),\n\n // Standalone compliance validation — used by dashboard wizard at step 2\n 'POST /profiles/validate': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:view')\n if (denied) return denied\n const body = await parseJsonBody(req) as { complianceGroup?: string; cookies?: Cookie[] }\n if (!body.complianceGroup || !Array.isArray(body.cookies)) {\n return errorResponse(400, 'complianceGroup and cookies are required')\n }\n return json(200, validateProfileCompliance(body.cookies, body.complianceGroup))\n }),\n\n // Returns active profile per compliance group for the coverage panel\n 'GET /compliance-coverage': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:view')\n if (denied) return denied\n const groups: Record<string, {\n label: string\n compliances: readonly string[]\n activeProfile: { id: string; name: string } | null\n }> = {}\n for (const [groupId, groupDef] of Object.entries(COMPLIANCE_GROUPS)) {\n const profile = await service.findActiveByComplianceGroup(groupId)\n groups[groupId] = {\n label: groupDef.label,\n compliances: groupDef.compliances,\n activeProfile: profile ? { id: profile.id, name: profile.name } : null,\n }\n }\n return json(200, { groups })\n }),\n\n 'POST /profiles': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:create')\n if (denied) return denied\n const body = await parseJsonBody(req) as Record<string, unknown>\n const validation = validateCreateProfile(body)\n if (!validation.valid) return errorResponse(400, validation.error ?? 'Invalid body')\n const input = castCreateProfile(body, 'default')\n\n // Compliance validation (defence in depth — dashboard already validates client-side)\n const complianceGroup = (input.profileJson as { complianceGroup?: string }).complianceGroup\n const choice = typeof body['choice'] === 'string' ? body['choice'] : undefined\n\n if (complianceGroup) {\n const cookies = (input.profileJson as { cookies?: Cookie[] }).cookies ?? []\n const complianceValidation = validateProfileCompliance(cookies, complianceGroup)\n if (!complianceValidation.valid) {\n return errorResponse(422, 'Profile does not meet compliance requirements', {\n errors: complianceValidation.errors,\n warnings: complianceValidation.warnings,\n })\n }\n\n // Conflict detection: only one active profile per compliance group\n const existing = await service.findActiveByComplianceGroup(complianceGroup)\n if (existing) {\n if (!choice) {\n return json(200, { conflict: { id: existing.id, name: existing.name }, requiresChoice: true })\n }\n if (choice === 'deactivate') {\n await service.deactivate(existing.id)\n }\n // choice === 'inactive' → fall through; new profile saves without isActive\n }\n\n const profile = await service.create(input)\n return json(201, { profile, warnings: complianceValidation.warnings })\n }\n\n const profile = await service.create(input)\n return json(201, profile)\n }),\n\n 'PUT /profiles/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:update')\n if (denied) return denied\n const id = p['id'] ?? ''\n const body = await parseJsonBody(req) as Record<string, unknown>\n const validation = validateUpdateProfile(body)\n if (!validation.valid) return errorResponse(400, validation.error ?? 'Invalid body')\n const input = castUpdateProfile(body)\n\n // Compliance validation\n const complianceGroup = (input.profileJson as { complianceGroup?: string } | undefined)?.complianceGroup\n const choice = typeof body['choice'] === 'string' ? body['choice'] : undefined\n\n if (complianceGroup) {\n const cookies = (input.profileJson as { cookies?: Cookie[] } | undefined)?.cookies ?? []\n const complianceValidation = validateProfileCompliance(cookies, complianceGroup)\n if (!complianceValidation.valid) {\n return errorResponse(422, 'Profile does not meet compliance requirements', {\n errors: complianceValidation.errors,\n warnings: complianceValidation.warnings,\n })\n }\n\n // Conflict detection: another active profile for same complianceGroup\n const existing = await service.findActiveByComplianceGroup(complianceGroup)\n if (existing && existing.id !== id) {\n if (!choice) {\n return json(200, { conflict: { id: existing.id, name: existing.name }, requiresChoice: true })\n }\n if (choice === 'deactivate') {\n await service.deactivate(existing.id)\n }\n }\n\n const profile = await service.update(id, input)\n return json(200, { profile, warnings: complianceValidation.warnings })\n }\n\n const profile = await service.update(id, input)\n return json(200, profile)\n }),\n\n 'DELETE /profiles/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:delete')\n if (denied) return denied\n await service.delete(p['id'] ?? '')\n return json(200, { success: true })\n }),\n\n 'POST /profiles/:id/activate': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:update')\n if (denied) return denied\n const id = p['id'] ?? ''\n const body = await parseJsonBody(req) as Record<string, unknown> | null\n const choice = typeof body?.['choice'] === 'string' ? body['choice'] : undefined\n\n const profile = await service.get(id)\n if (!profile) return errorResponse(404, 'Profile not found')\n\n const complianceGroup = (profile.profileJson as { complianceGroup?: string }).complianceGroup\n if (complianceGroup) {\n const existing = await service.findActiveByComplianceGroup(complianceGroup)\n if (existing && existing.id !== id) {\n if (!choice) {\n return json(200, { conflict: { id: existing.id, name: existing.name }, requiresChoice: true })\n }\n if (choice === 'deactivate') {\n await service.deactivate(existing.id)\n }\n }\n }\n\n const activated = await service.activate(id)\n return json(200, activated)\n }),\n\n 'POST /profiles/:id/deactivate': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:update')\n if (denied) return denied\n const profile = await service.deactivate(p['id'] ?? '')\n return json(200, profile)\n }),\n\n 'GET /profiles/:id/versions': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:view')\n if (denied) return denied\n return json(200, service.listVersions(p['id'] ?? ''))\n }),\n\n 'GET /profiles/:id/versions/:version': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:view')\n if (denied) return denied\n const url = new URL(req.url)\n const locale = url.searchParams.get('locale') ?? 'default'\n const ver = parseInt(p['version'] ?? '0', 10)\n if (isNaN(ver) || ver < 1) return errorResponse(400, 'Invalid version number')\n const content = service.getVersionFile(p['id'] ?? '', ver, locale)\n if (!content) return errorResponse(404, 'Version file not found')\n return new Response(content, { headers: { 'Content-Type': 'application/json' } })\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig, ConsentFilters } from '@consenti/types'\nimport { json, getQueryParam, getQueryInt } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\n\nexport function buildAdminConsentRoutes(\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request, perm?: string) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { user, denied: authError(user, perm) }\n }\n\n return {\n 'GET /consents': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user, denied } = await auth(req, 'consent:view')\n if (denied) return denied\n if (user?.allowedTenants.length && !user.allowedTenants.includes('default')) return json(200, { items: [], total: 0, page: 1, limit: 50 })\n const url = new URL(req.url)\n const profileId = getQueryParam(url, 'profileId')\n const from = getQueryParam(url, 'from')\n const to = getQueryParam(url, 'to')\n const limit = getQueryInt(url, 'limit', 50)\n if (limit > 500) return errorResponse(400, 'limit must not exceed 500')\n const filters: ConsentFilters = {\n tenantId: 'default',\n page: getQueryInt(url, 'page', 1),\n limit,\n ...(profileId !== undefined ? { profileId } : {}),\n ...(from !== undefined ? { from } : {}),\n ...(to !== undefined ? { to } : {}),\n }\n const records = await storage.getConsents(filters)\n return json(200, records)\n }),\n\n 'GET /consents/:visitorId': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user, denied } = await auth(req, 'consent:view')\n if (denied) return denied\n if (user?.allowedTenants.length && !user.allowedTenants.includes('default')) return errorResponse(403, 'Forbidden')\n const record = await storage.getConsent(p['visitorId'] ?? '')\n if (!record) return errorResponse(404, 'Consent not found')\n return json(200, record)\n }),\n\n 'GET /consents/:visitorId/history': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user, denied } = await auth(req, 'consent:view')\n if (denied) return denied\n if (user?.allowedTenants.length && !user.allowedTenants.includes('default')) return errorResponse(403, 'Forbidden')\n const history = await storage.getConsentHistory(p['visitorId'] ?? '')\n return json(200, history)\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig, VisitorFilters } from '@consenti/types'\nimport { json, getQueryInt, getQueryParam } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\n\nexport function buildAdminVisitorRoutes(\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request, perm?: string) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { user, denied: authError(user, perm) }\n }\n\n return {\n 'GET /visitors': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user, denied } = await auth(req, 'visitor:view')\n if (denied) return denied\n if (user?.allowedTenants.length && !user.allowedTenants.includes('default')) return json(200, { items: [], total: 0, page: 1, limit: 50 })\n const url = new URL(req.url)\n const from = getQueryParam(url, 'from')\n const to = getQueryParam(url, 'to')\n const limit = getQueryInt(url, 'limit', 50)\n if (limit > 500) return errorResponse(400, 'limit must not exceed 500')\n const filters: VisitorFilters = {\n tenantId: 'default',\n page: getQueryInt(url, 'page', 1),\n limit,\n ...(from !== undefined ? { from } : {}),\n ...(to !== undefined ? { to } : {}),\n }\n const visitors = await storage.getVisitors(filters)\n return json(200, visitors)\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig } from '@consenti/types'\nimport { json, parseJsonBody } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\nimport type { UserService } from '../../services/user.service'\n\nexport function buildAdminUserRoutes(\n userService: UserService,\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request, perm?: string) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { user, denied: authError(user, perm) }\n }\n\n return {\n 'GET /users': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'user:view')\n if (denied) return denied\n const users = await userService.list()\n return json(200, users)\n }),\n\n 'GET /users/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'user:view')\n if (denied) return denied\n const user = await userService.get(p['id'] ?? '')\n if (!user) return errorResponse(404, 'User not found')\n const roles = await userService.getRoles(user.id)\n return json(200, { ...user, roles: roles.map(r => ({ id: r.id, name: r.name })) })\n }),\n\n 'POST /users': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user: actor, denied } = await auth(req, 'user:create')\n if (denied) return denied\n const body = await parseJsonBody(req)\n if (!body || typeof body !== 'object') return errorResponse(400, 'Invalid body')\n const b = body as Record<string, unknown>\n if (typeof b['name'] !== 'string' || !b['name']) return errorResponse(400, 'name is required')\n if (typeof b['email'] !== 'string' || !b['email']) return errorResponse(400, 'email is required')\n if (typeof b['password'] !== 'string' || !b['password']) return errorResponse(400, 'password is required')\n if (b['password'].length < 12) return errorResponse(400, 'password must be at least 12 characters')\n const created = await userService.create(\n {\n name: b['name'],\n email: b['email'],\n password: b['password'],\n ...(typeof b['roleId'] === 'string' ? { roleId: b['roleId'] } : {}),\n ...(Array.isArray(b['allowedTenants']) ? { allowedTenants: b['allowedTenants'] as string[] } : {}),\n },\n actor!.sub,\n )\n return json(201, created)\n }),\n\n 'PUT /users/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user: actor, denied } = await auth(req, 'user:update')\n if (denied) return denied\n const id = p['id'] ?? ''\n const body = await parseJsonBody(req)\n if (!body || typeof body !== 'object') return errorResponse(400, 'Invalid body')\n const b = body as Record<string, unknown>\n if (typeof b['password'] === 'string' && b['password'].length < 12) {\n return errorResponse(400, 'password must be at least 12 characters')\n }\n const updated = await userService.update(\n id,\n {\n ...(typeof b['name'] === 'string' ? { name: b['name'] } : {}),\n ...(typeof b['email'] === 'string' ? { email: b['email'] } : {}),\n ...(b['isActive'] != null ? { isActive: Boolean(b['isActive']) } : {}),\n ...(typeof b['password'] === 'string' ? { password: b['password'] } : {}),\n ...(Array.isArray(b['allowedTenants']) ? { allowedTenants: b['allowedTenants'] as string[] } : {}),\n },\n actor!.sub,\n )\n return json(200, updated)\n }),\n\n 'DELETE /users/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user: actor, denied } = await auth(req, 'user:delete')\n if (denied) return denied\n const id = p['id'] ?? ''\n if (id === actor!.sub) return errorResponse(400, 'Cannot delete your own account')\n await userService.delete(id, actor!.sub)\n return json(200, { success: true })\n }),\n\n 'POST /users/:id/roles': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user: actor, denied } = await auth(req, 'role:update')\n if (denied) return denied\n const body = await parseJsonBody(req)\n if (!body || typeof body !== 'object') return errorResponse(400, 'Invalid body')\n const b = body as Record<string, unknown>\n if (typeof b['roleId'] !== 'string') return errorResponse(400, 'roleId is required')\n const tenantId = typeof b['tenantId'] === 'string' ? b['tenantId'] : undefined\n await userService.assignRole(p['id'] ?? '', b['roleId'], tenantId)\n await storage.createLog({\n tenantId: 'default',\n userId: actor!.sub,\n action: 'user.role_assigned',\n resourceType: 'user',\n ...(p['id'] != null ? { resourceId: p['id'] } : {}),\n newData: { roleId: b['roleId'] },\n })\n return json(200, { success: true })\n }),\n\n 'DELETE /users/:id/roles/:roleId': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user: actor, denied } = await auth(req, 'role:update')\n if (denied) return denied\n const url = new URL(req.url)\n const revokedTenantId = url.searchParams.get('tenantId') ?? undefined\n await userService.revokeRole(p['id'] ?? '', p['roleId'] ?? '', revokedTenantId)\n await storage.createLog({\n tenantId: 'default',\n userId: actor!.sub,\n action: 'user.role_revoked',\n resourceType: 'user',\n ...(p['id'] != null ? { resourceId: p['id'] } : {}),\n oldData: { roleId: p['roleId'] },\n })\n return json(200, { success: true })\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig } from '@consenti/types'\nimport { json, parseJsonBody } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\n\nexport function buildAdminRoleRoutes(\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request, perm?: string) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { user, denied: authError(user, perm) }\n }\n\n return {\n 'GET /roles': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'role:view')\n if (denied) return denied\n const roles = await storage.getRoles('default')\n return json(200, roles)\n }),\n\n 'GET /roles/:id/permissions': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'role:view')\n if (denied) return denied\n const perms = await storage.getPermissionsForRole(p['id'] ?? '')\n return json(200, perms)\n }),\n\n 'POST /roles': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user: actor, denied } = await auth(req, 'role:create')\n if (denied) return denied\n const body = await parseJsonBody(req)\n if (!body || typeof body !== 'object') return errorResponse(400, 'Invalid body')\n const b = body as Record<string, unknown>\n if (typeof b['name'] !== 'string' || !b['name']) return errorResponse(400, 'name is required')\n const role = await storage.createRole({\n tenantId: 'default',\n name: b['name'],\n ...(typeof b['description'] === 'string' ? { description: b['description'] } : {}),\n })\n await storage.createLog({\n tenantId: 'default',\n userId: actor!.sub,\n action: 'role.created',\n resourceType: 'role',\n resourceId: role.id,\n newData: role,\n })\n return json(201, role)\n }),\n\n 'PUT /roles/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user: actor, denied } = await auth(req, 'role:update')\n if (denied) return denied\n const body = await parseJsonBody(req)\n if (!body || typeof body !== 'object') return errorResponse(400, 'Invalid body')\n const b = body as Record<string, unknown>\n const role = await storage.updateRole(p['id'] ?? '', {\n ...(typeof b['name'] === 'string' ? { name: b['name'] } : {}),\n ...(typeof b['description'] === 'string' ? { description: b['description'] } : {}),\n })\n await storage.createLog({\n tenantId: 'default',\n userId: actor!.sub,\n action: 'role.updated',\n resourceType: 'role',\n resourceId: role.id,\n newData: role,\n })\n return json(200, role)\n }),\n\n 'DELETE /roles/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user: actor, denied } = await auth(req, 'role:delete')\n if (denied) return denied\n await storage.deleteRole(p['id'] ?? '')\n await storage.createLog({\n tenantId: 'default',\n userId: actor!.sub,\n action: 'role.deleted',\n resourceType: 'role',\n ...(p['id'] != null ? { resourceId: p['id'] } : {}),\n })\n return json(200, { success: true })\n }),\n\n 'GET /permissions': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'role:view')\n if (denied) return denied\n const perms = await storage.getAllPermissions()\n return json(200, perms)\n }),\n\n 'POST /roles/:id/permissions': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'role:update')\n if (denied) return denied\n const body = await parseJsonBody(req)\n if (!body || typeof body !== 'object') return errorResponse(400, 'Invalid body')\n const b = body as Record<string, unknown>\n if (typeof b['permissionId'] !== 'string') return errorResponse(400, 'permissionId is required')\n await storage.assignPermissionToRole(p['id'] ?? '', b['permissionId'])\n return json(200, { success: true })\n }),\n\n 'DELETE /roles/:id/permissions/:permissionId': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'role:update')\n if (denied) return denied\n await storage.revokePermissionFromRole(p['id'] ?? '', p['permissionId'] ?? '')\n return json(200, { success: true })\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig, AuditFilters } from '@consenti/types'\nimport { json, getQueryParam, getQueryInt } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\n\nexport function buildAdminAuditRoutes(\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request, perm?: string) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { user, denied: authError(user, perm) }\n }\n\n return {\n 'GET /audit': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { user, denied } = await auth(req, 'audit:view')\n if (denied) return denied\n if (user?.allowedTenants.length && !user.allowedTenants.includes('default')) return json(200, { items: [], total: 0, page: 1, limit: 50 })\n const url = new URL(req.url)\n const action = getQueryParam(url, 'action')\n const resourceType = getQueryParam(url, 'resourceType')\n const from = getQueryParam(url, 'from')\n const to = getQueryParam(url, 'to')\n const limit = getQueryInt(url, 'limit', 50)\n if (limit > 500) return errorResponse(400, 'limit must not exceed 500')\n const filters: AuditFilters = {\n tenantId: 'default',\n page: getQueryInt(url, 'page', 1),\n limit,\n ...(action !== undefined ? { action } : {}),\n ...(resourceType !== undefined ? { resourceType } : {}),\n ...(from !== undefined ? { from } : {}),\n ...(to !== undefined ? { to } : {}),\n }\n const logs = await storage.getLogs(filters)\n return json(200, logs)\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig } from '@consenti/types'\nimport { json, getQueryInt } from '../../utils/http'\nimport { withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\n\nexport function buildAdminStatsRoutes(\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { denied: authError(user, 'consent:view') }\n }\n\n return {\n 'GET /stats/overview': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const stats = await storage.getOverviewStats('default')\n return json(200, stats)\n }),\n\n 'GET /stats/categories': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const stats = await storage.getCategoryStats('default')\n return json(200, stats)\n }),\n\n 'GET /stats/timeline': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const url = new URL(req.url)\n const days = getQueryInt(url, 'days', 30)\n const timeline = await storage.getTimeline('default', days)\n return json(200, timeline)\n }),\n\n 'GET /stats/countries': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const countries = await storage.getCountries('default')\n return json(200, countries)\n }),\n\n 'GET /stats/gpc': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const gpc = await storage.getGpcStats('default')\n return json(200, gpc)\n }),\n\n 'GET /stats/aggregate': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const tenants = await storage.getTenants()\n const rows = await Promise.all(\n tenants.map(async t => {\n const s = await storage.getOverviewStats(t.id)\n return { tenantId: t.id, tenantName: t.name, ...s }\n }),\n )\n const aggregate = rows.reduce(\n (acc, r) => ({\n totalConsents: acc.totalConsents + r.totalConsents,\n totalVisitors: acc.totalVisitors + r.totalVisitors,\n gpcDetectedCount: acc.gpcDetectedCount + r.gpcDetectedCount,\n }),\n { totalConsents: 0, totalVisitors: 0, gpcDetectedCount: 0 },\n )\n return json(200, { aggregate, perTenant: rows })\n }),\n }\n}\n","import type {\n StorageAdapter, AuthConfig, ConsentFilters, AuditFilters,\n ConsentDbRecord, AuditLog,\n} from '@consenti/types'\nimport { withErrorHandler } from '../../middleware/error.middleware'\nimport { errorResponse } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\nimport { getQueryParam } from '../../utils/http'\n\nfunction escapeCsv(val: string | number | boolean | null | undefined): string {\n const s = val == null ? '' : String(val)\n if (s.includes(',') || s.includes('\"') || s.includes('\\n')) {\n return `\"${s.replace(/\"/g, '\"\"')}\"`\n }\n return s\n}\n\nfunction consentToCsvRow(r: ConsentDbRecord): string {\n return [\n r.id, r.visitorId, r.profileId, r.profileVersion, r.locale,\n JSON.stringify(r.consentJson), r.gpcDetected ? '1' : '0',\n r.source, r.createdAt, r.updatedAt,\n ].map(escapeCsv).join(',') + '\\n'\n}\n\nfunction auditToCsvRow(r: AuditLog): string {\n return [\n r.id, r.userId ?? '', r.action, r.resourceType, r.resourceId ?? '', r.createdAt,\n ].map(escapeCsv).join(',') + '\\n'\n}\n\nexport function buildAdminExportRoutes(\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { denied: authError(user, 'export:run') }\n }\n\n return {\n 'GET /export/consents': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const url = new URL(req.url)\n const format = getQueryParam(url, 'format') ?? 'csv'\n const profileId = getQueryParam(url, 'profileId')\n const from = getQueryParam(url, 'from')\n const to = getQueryParam(url, 'to')\n const filters: ConsentFilters = {\n tenantId: 'default',\n ...(profileId !== undefined ? { profileId } : {}),\n ...(from !== undefined ? { from } : {}),\n ...(to !== undefined ? { to } : {}),\n }\n\n if (format === 'json') {\n const records: ConsentDbRecord[] = []\n for await (const r of storage.streamConsents(filters)) records.push(r)\n return new Response(JSON.stringify(records), {\n status: 200,\n headers: {\n 'Content-Type': 'application/json',\n 'Content-Disposition': 'attachment; filename=\"consents.json\"',\n },\n })\n }\n\n const enc = new TextEncoder()\n const header = 'id,visitor_id,profile_id,profile_version,locale,consent_json,gpc_detected,source,created_at,updated_at\\n'\n const stream = new ReadableStream({\n async start(controller) {\n controller.enqueue(enc.encode(header))\n for await (const r of storage.streamConsents(filters)) {\n controller.enqueue(enc.encode(consentToCsvRow(r)))\n }\n controller.close()\n },\n })\n return new Response(stream, {\n status: 200,\n headers: {\n 'Content-Type': 'text/csv; charset=utf-8',\n 'Content-Disposition': 'attachment; filename=\"consents.csv\"',\n },\n })\n }),\n\n 'GET /export/consents/xlsx': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n\n interface XlsxModule {\n utils: {\n book_new(): object\n json_to_sheet(rows: object[]): object\n book_append_sheet(wb: object, ws: object, name: string): void\n }\n write(wb: object, opts: { type: string; bookType: string }): Uint8Array\n }\n let XlsxMod: XlsxModule | null = null\n try {\n // @ts-expect-error -- xlsx is an optional peer dependency; install it to use XLSX export\n XlsxMod = (await import('xlsx')) as XlsxModule\n } catch {\n return new Response(JSON.stringify({ error: 'xlsx peer dependency not installed. Run: npm install xlsx' }), {\n status: 501,\n headers: { 'Content-Type': 'application/json' },\n })\n }\n if (!XlsxMod) return new Response(null, { status: 501 })\n\n const url = new URL(req.url)\n const profileId = url.searchParams.get('profileId') ?? undefined\n const from = url.searchParams.get('from') ?? undefined\n const to = url.searchParams.get('to') ?? undefined\n const filters: ConsentFilters = {\n tenantId: 'default',\n ...(profileId !== undefined ? { profileId } : {}),\n ...(from !== undefined ? { from } : {}),\n ...(to !== undefined ? { to } : {}),\n }\n\n const rows: Record<string, unknown>[] = []\n for await (const r of storage.streamConsents(filters)) {\n rows.push({\n id: r.id,\n visitor_id: r.visitorId,\n profile_id: r.profileId,\n profile_version: r.profileVersion,\n locale: r.locale,\n consent_json: JSON.stringify(r.consentJson),\n gpc_detected: r.gpcDetected ? 1 : 0,\n age_verified: r.ageVerified ? 1 : 0,\n tcf_string: r.tcfString ?? '',\n source: r.source,\n created_at: r.createdAt,\n updated_at: r.updatedAt,\n })\n }\n\n const wb = XlsxMod.utils.book_new()\n const ws = XlsxMod.utils.json_to_sheet(rows)\n XlsxMod.utils.book_append_sheet(wb, ws, 'Consents')\n const buf = XlsxMod.write(wb, { type: 'buffer', bookType: 'xlsx' })\n return new Response(buf as unknown as BodyInit, {\n status: 200,\n headers: {\n 'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n 'Content-Disposition': 'attachment; filename=\"consents.xlsx\"',\n },\n })\n }),\n\n 'GET /export/translations/:profileId': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const profileId = p['profileId'] ?? ''\n const profile = await storage.getProfile(profileId)\n if (!profile) return errorResponse(404, 'Profile not found')\n\n const translations = profile.profileJson.translations ?? {}\n const locales = Object.keys(translations)\n if (locales.length === 0) {\n return new Response('locale,field,value\\n', {\n status: 200,\n headers: {\n 'Content-Type': 'text/csv; charset=utf-8',\n 'Content-Disposition': `attachment; filename=\"${profileId}-translations.csv\"`,\n },\n })\n }\n\n const rows: string[] = ['locale,section,field,value']\n for (const locale of locales) {\n const t = translations[locale]\n if (!t) continue\n for (const [section, content] of Object.entries(t)) {\n if (typeof content === 'object' && content !== null) {\n for (const [field, value] of Object.entries(content as Record<string, unknown>)) {\n if (typeof value === 'string') {\n rows.push([locale, section, field, value].map(escapeCsv).join(','))\n }\n }\n }\n }\n }\n\n return new Response(rows.join('\\n') + '\\n', {\n status: 200,\n headers: {\n 'Content-Type': 'text/csv; charset=utf-8',\n 'Content-Disposition': `attachment; filename=\"${profileId}-translations.csv\"`,\n },\n })\n }),\n\n 'GET /export/audit': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const url = new URL(req.url)\n const format = getQueryParam(url, 'format') ?? 'csv'\n const from = getQueryParam(url, 'from')\n const to = getQueryParam(url, 'to')\n const filters: AuditFilters = {\n tenantId: 'default',\n ...(from !== undefined ? { from } : {}),\n ...(to !== undefined ? { to } : {}),\n }\n\n if (format === 'json') {\n const logs: AuditLog[] = []\n for await (const r of storage.streamAuditLogs(filters)) logs.push(r)\n return new Response(JSON.stringify(logs), {\n status: 200,\n headers: {\n 'Content-Type': 'application/json',\n 'Content-Disposition': 'attachment; filename=\"audit.json\"',\n },\n })\n }\n\n const enc = new TextEncoder()\n const header = 'id,user_id,action,resource_type,resource_id,created_at\\n'\n const stream = new ReadableStream({\n async start(controller) {\n controller.enqueue(enc.encode(header))\n for await (const r of storage.streamAuditLogs(filters)) {\n controller.enqueue(enc.encode(auditToCsvRow(r)))\n }\n controller.close()\n },\n })\n return new Response(stream, {\n status: 200,\n headers: {\n 'Content-Type': 'text/csv; charset=utf-8',\n 'Content-Disposition': 'attachment; filename=\"audit.csv\"',\n },\n })\n }),\n }\n}\n","import { randomBytes, createHash } from 'node:crypto'\nimport type { StorageAdapter, AuthConfig } from '@consenti/types'\nimport { json } from '../../utils/http'\nimport { withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\n\nfunction generateApiKey(): { raw: string; hash: string } {\n const raw = `ck_live_${randomBytes(24).toString('hex')}`\n const hash = createHash('sha256').update(raw).digest('hex')\n return { raw, hash }\n}\n\nexport function buildAdminApiKeyRoutes(\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { user, denied: authError(user, 'settings:update') }\n }\n\n return {\n 'GET /apikeys': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const keys = await storage.getApiKeys('default')\n return json(200, keys.map(k => ({ id: k.id, name: k.name, isActive: k.isActive, createdAt: k.createdAt })))\n }),\n\n 'POST /apikeys': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const body = await req.json() as { name?: string; tenantId?: string }\n if (!body.name) return json(400, { error: 'name is required' })\n const { raw, hash } = generateApiKey()\n const created = await storage.createApiKey({ tenantId: body.tenantId ?? 'default', name: body.name, keyHash: hash })\n return json(201, { id: created.id, name: created.name, key: raw, createdAt: created.createdAt })\n }),\n\n 'DELETE /apikeys/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n await storage.revokeApiKey(p['id'] ?? '')\n return json(204, null)\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig } from '@consenti/types'\nimport { json, parseJsonBody } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\n\nexport function buildAdminTenantRoutes(\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request, perm: string) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { user, denied: authError(user, perm) }\n }\n\n return {\n 'GET /tenants': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'settings:update')\n if (denied) return denied\n const tenants = await storage.getTenants()\n return json(200, tenants)\n }),\n\n 'POST /tenants': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'settings:update')\n if (denied) return denied\n const body = await parseJsonBody(req)\n if (!body || typeof body !== 'object') return errorResponse(400, 'Invalid body')\n const b = body as Record<string, unknown>\n if (typeof b['name'] !== 'string' || typeof b['slug'] !== 'string') {\n return errorResponse(400, 'name and slug are required')\n }\n const tenant = await storage.createTenant({ name: b['name'], slug: b['slug'] })\n return json(201, tenant)\n }),\n\n 'PUT /tenants/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'settings:update')\n if (denied) return denied\n const body = await parseJsonBody(req)\n if (!body || typeof body !== 'object') return errorResponse(400, 'Invalid body')\n const b = body as Record<string, unknown>\n const tenant = await storage.updateTenant(p['id'] ?? '', {\n ...(typeof b['name'] === 'string' ? { name: b['name'] } : {}),\n ...(typeof b['slug'] === 'string' ? { slug: b['slug'] } : {}),\n })\n return json(200, tenant)\n }),\n\n 'DELETE /tenants/:id': async (req: Request, p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'settings:update')\n if (denied) return denied\n const id = p['id'] ?? ''\n if (id === 'default') return errorResponse(400, 'Cannot delete the default tenant')\n await storage.deleteTenant(id)\n return json(200, { success: true })\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig } from '@consenti/types'\nimport { getGvl } from '../../tcf/gvl-cache'\nimport { json } from '../../utils/http'\nimport { withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\n\nexport function buildAdminTcfRoutes(\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n) {\n async function auth(req: Request) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { denied: authError(user, 'consent:view') }\n }\n\n return {\n 'GET /tcf/vendors': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const gvl = await getGvl()\n if (!gvl) return json(503, { error: 'GVL not available. Enable tcf.enabled in config.' })\n const url = new URL(req.url)\n const search = url.searchParams.get('q')?.toLowerCase()\n const page = Math.max(1, parseInt(url.searchParams.get('page') ?? '1', 10))\n const limit = Math.min(200, Math.max(1, parseInt(url.searchParams.get('limit') ?? '100', 10)))\n const vendors = Object.values(gvl.vendors)\n const filtered = search\n ? vendors.filter(v => v.name.toLowerCase().includes(search))\n : vendors\n const total = filtered.length\n const totalPages = Math.max(1, Math.ceil(total / limit))\n const safePage = Math.min(page, totalPages)\n const start = (safePage - 1) * limit\n return json(200, {\n vendorListVersion: gvl.vendorListVersion,\n total,\n page: safePage,\n totalPages,\n vendors: filtered.slice(start, start + limit),\n })\n }),\n\n 'GET /tcf/purposes': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req)\n if (denied) return denied\n const gvl = await getGvl()\n if (!gvl) return json(503, { error: 'GVL not available. Enable tcf.enabled in config.' })\n return json(200, { purposes: Object.values(gvl.purposes) })\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig, Cookie } from '@consenti/types'\nimport { json, parseJsonBody } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\nimport { validateProfileCompliance } from '../../services/compliance-validator.service'\n\nexport function buildAdminCookieTemplateRoutes(storage: StorageAdapter, authConfig: AuthConfig, secret: string, tenantId = 'default') {\n async function auth(req: Request, perm?: string) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { user, denied: authError(user, perm) }\n }\n\n return {\n 'GET /cookie-templates': async (req: Request): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:view')\n if (denied) return denied\n return json(200, await storage.getCookieTemplates(tenantId))\n }),\n\n 'GET /cookie-templates/:id': async (req: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:view')\n if (denied) return denied\n const t = await storage.getCookieTemplate(params['id']!)\n return t ? json(200, t) : errorResponse(404, 'Cookie template not found')\n }),\n\n 'POST /cookie-templates': async (req: Request): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:create')\n if (denied) return denied\n const body = await parseJsonBody<{ name?: unknown; cookies?: unknown }>(req)\n if (!body?.name || typeof body.name !== 'string') return errorResponse(400, 'name is required')\n if (!Array.isArray(body.cookies)) return errorResponse(400, 'cookies must be an array')\n const t = await storage.createCookieTemplate({ tenantId, name: body.name, cookies: body.cookies as never })\n return json(201, t)\n }),\n\n 'PUT /cookie-templates/:id': async (req: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:update')\n if (denied) return denied\n const id = params['id']!\n const body = await parseJsonBody<{ name?: unknown; cookies?: unknown }>(req)\n const update: { name?: string; cookies?: never } = {}\n if (body?.name !== undefined && typeof body.name === 'string') update.name = body.name\n if (body?.cookies !== undefined && Array.isArray(body.cookies)) update.cookies = body.cookies as never\n\n // Cookie removal validation: if cookies were removed, check against profiles' compliance rules\n if (Array.isArray(body?.cookies)) {\n const oldTemplate = await storage.getCookieTemplate(id)\n if (oldTemplate) {\n const newCookieIds = new Set((body.cookies as Cookie[]).map(c => c.id))\n const removedIds = oldTemplate.cookies.map(c => c.id).filter(cid => !newCookieIds.has(cid))\n if (removedIds.length > 0) {\n const profiles = await storage.findProfilesUsingCookieTemplate(id)\n const blockingProfiles: { id: string; name: string; complianceGroup: string }[] = []\n for (const p of profiles) {\n if (!p.complianceGroup) continue\n const result = validateProfileCompliance(body.cookies as Cookie[], p.complianceGroup)\n if (!result.valid) {\n blockingProfiles.push({ id: p.id, name: p.name, complianceGroup: p.complianceGroup })\n }\n }\n if (blockingProfiles.length > 0) {\n return errorResponse(422, 'Removing these cookies would break compliance for affected profiles', {\n blockingProfiles,\n removedCookieIds: removedIds,\n })\n }\n }\n }\n }\n\n const t = await storage.updateCookieTemplate(id, update)\n return json(200, t)\n }),\n\n 'DELETE /cookie-templates/:id': async (req: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:delete')\n if (denied) return denied\n const id = params['id']!\n const profiles = await storage.findProfilesUsingCookieTemplate(id)\n if (profiles.length > 0) {\n return errorResponse(422, 'Cannot delete: template is used by profiles', {\n profiles: profiles.map(p => ({ id: p.id, name: p.name, isActive: p.isActive })),\n })\n }\n await storage.deleteCookieTemplate(id)\n return json(200, { ok: true })\n }),\n\n 'POST /cookie-templates/:id/copy': async (req: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:create')\n if (denied) return denied\n const body = await parseJsonBody<{ name?: unknown }>(req)\n const src = await storage.getCookieTemplate(params['id']!)\n if (!src) return errorResponse(404, 'Cookie template not found')\n const newName = (typeof body?.name === 'string' && body.name.trim()) ? body.name.trim() : `${src.name} (Copy)`\n const t = await storage.copyCookieTemplate(params['id']!, newName)\n return json(201, t)\n }),\n\n 'GET /cookie-templates/:id/profile-usage': async (req: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:view')\n if (denied) return denied\n const usage = await storage.findProfilesUsingCookieTemplate(params['id']!)\n return json(200, usage)\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig } from '@consenti/types'\nimport { json, parseJsonBody } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\n\nexport function buildAdminUITemplateRoutes(storage: StorageAdapter, authConfig: AuthConfig, secret: string, tenantId = 'default') {\n async function auth(req: Request, perm?: string) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { user, denied: authError(user, perm) }\n }\n\n return {\n 'GET /ui-templates': async (req: Request): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:view')\n if (denied) return denied\n return json(200, await storage.getUITemplates(tenantId))\n }),\n\n 'GET /ui-templates/:id': async (req: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:view')\n if (denied) return denied\n const t = await storage.getUITemplate(params['id']!)\n return t ? json(200, t) : errorResponse(404, 'UI template not found')\n }),\n\n 'POST /ui-templates': async (req: Request): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:create')\n if (denied) return denied\n const body = await parseJsonBody<Record<string, unknown>>(req)\n if (!body?.name || typeof body.name !== 'string') return errorResponse(400, 'name is required')\n if (!body.mainBanner || !body.gpcBanner || !body.preferenceModal) return errorResponse(400, 'mainBanner, gpcBanner, and preferenceModal are required')\n const t = await storage.createUITemplate({\n tenantId,\n name: body.name,\n mainBanner: body.mainBanner as never,\n gpcBanner: body.gpcBanner as never,\n preferenceModal: body.preferenceModal as never,\n })\n return json(201, t)\n }),\n\n 'PUT /ui-templates/:id': async (req: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:update')\n if (denied) return denied\n const body = await parseJsonBody<Record<string, unknown>>(req)\n const update: Record<string, unknown> = {}\n if (typeof body?.name === 'string') update['name'] = body.name\n if (body?.mainBanner) update['mainBanner'] = body.mainBanner\n if (body?.gpcBanner) update['gpcBanner'] = body.gpcBanner\n if (body?.preferenceModal) update['preferenceModal'] = body.preferenceModal\n const t = await storage.updateUITemplate(params['id']!, update as never)\n return json(200, t)\n }),\n\n 'DELETE /ui-templates/:id': async (req: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:delete')\n if (denied) return denied\n const id = params['id']!\n const profiles = await storage.findProfilesUsingUITemplate(id)\n if (profiles.length > 0) {\n return errorResponse(422, 'Cannot delete: template is used by profiles', {\n profiles: profiles.map(p => ({ id: p.id, name: p.name, isActive: p.isActive })),\n })\n }\n await storage.deleteUITemplate(id)\n return json(200, { ok: true })\n }),\n\n 'POST /ui-templates/:id/copy': async (req: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:create')\n if (denied) return denied\n const body = await parseJsonBody<{ name?: unknown }>(req)\n const src = await storage.getUITemplate(params['id']!)\n if (!src) return errorResponse(404, 'UI template not found')\n const newName = (typeof body?.name === 'string' && body.name.trim()) ? body.name.trim() : `${src.name} (Copy)`\n const t = await storage.copyUITemplate(params['id']!, newName)\n return json(201, t)\n }),\n\n 'GET /ui-templates/:id/profile-usage': async (req: Request, params: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'profile:view')\n if (denied) return denied\n const usage = await storage.findProfilesUsingUITemplate(params['id']!)\n return json(200, usage)\n }),\n }\n}\n","import type { StorageAdapter, AuthConfig, OptInFilters } from '@consenti/types'\nimport { json } from '../../utils/http'\nimport { errorResponse, withErrorHandler } from '../../middleware/error.middleware'\nimport { authenticate, authError } from '../../middleware/auth.middleware'\n\nexport function buildAdminAnalyticsRoutes(\n storage: StorageAdapter,\n authConfig: AuthConfig,\n secret: string,\n defaultTenantId = 'default',\n) {\n async function auth(req: Request, perm?: string) {\n const user = await authenticate(req, storage, authConfig, secret)\n return { user, denied: authError(user, perm) }\n }\n\n return {\n 'GET /analytics/opt-in': async (req: Request, _p: Record<string, string>): Promise<Response> =>\n withErrorHandler(async () => {\n const { denied } = await auth(req, 'stats:view')\n if (denied) return denied\n\n const url = new URL(req.url)\n const tenantId = url.searchParams.get('tenantId') ?? defaultTenantId\n\n const filters: OptInFilters = {}\n const profileId = url.searchParams.get('profileId')\n const complianceGroup = url.searchParams.get('complianceGroup')\n const from = url.searchParams.get('from')\n const to = url.searchParams.get('to')\n const locale = url.searchParams.get('locale')\n\n if (profileId) filters.profileId = profileId\n if (complianceGroup) filters.complianceGroup = complianceGroup\n if (from) filters.from = from\n if (to) filters.to = to\n if (locale) filters.locale = locale\n\n const stats = await storage.getOptInStats(tenantId, filters)\n return json(200, stats)\n }),\n }\n}\n","import { createHash } from 'node:crypto'\nimport type { StorageAdapter } from '@consenti/types'\n\nexport async function resolveTenant(\n req: Request,\n storage: StorageAdapter,\n defaultTenantId: string,\n): Promise<string> {\n const auth = req.headers.get('authorization')\n if (!auth?.startsWith('Bearer ck_')) return defaultTenantId\n\n const rawKey = auth.slice(7)\n const keyHash = createHash('sha256').update(rawKey).digest('hex')\n const apiKey = await storage.getApiKeyByHash(keyHash)\n return apiKey?.tenantId ?? defaultTenantId\n}\n","interface RateLimitEntry {\n count: number\n resetAt: number\n}\n\nexport class RateLimiter {\n private store = new Map<string, RateLimitEntry>()\n\n constructor(\n private windowMs: number = 60_000,\n private maxRequests: number = 60,\n ) {\n setInterval(() => {\n const now = Date.now()\n for (const [key, entry] of this.store) {\n if (now >= entry.resetAt) this.store.delete(key)\n }\n }, this.windowMs).unref()\n }\n\n check(key: string): boolean {\n const now = Date.now()\n const entry = this.store.get(key)\n\n if (!entry || now >= entry.resetAt) {\n this.store.set(key, { count: 1, resetAt: now + this.windowMs })\n return true\n }\n\n entry.count += 1\n return entry.count <= this.maxRequests\n }\n\n // Returns false if either the IP bucket or the profileId bucket is exhausted.\n checkRequest(ip: string, profileId?: string): boolean {\n const ipOk = this.check(`ip:${ip}`)\n if (!ipOk) return false\n if (profileId) return this.check(`profile:${profileId}`)\n return true\n }\n}\n"],"mappings":"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","names":["index_exports","__export","MongoDBAdapter","MySQLAdapter","PostgreSQLAdapter","BetterSqlite3Adapter","createConsenti","dashboardDir","__toCommonJS","getImportMetaUrl","importMetaUrl","import_node_events","import_promises","import_node_path","import_node_url","PluginEngine","plugins","context","plugin","err","data","result","record","profile","user","import_node_fs","import_node_path","buildConsentiRuntimeConfig","dashboardDir","basePath","branding","compliance","resolvedCompliance","buildConsentiConfigScript","cfg","injectConfigScript","html","script","str","GVL_URL","cachedGvl","lastFetched","refreshTimer","isGvlData","d","getGvl","res","GVL_URL","data","startGvlRefresh","stopGvlRefresh","SHARED_SCHEMAS","OPENAPI_PUBLIC_SPEC","OPENAPI_ADMIN_SPEC","import_node_crypto","randomProfileId","hashIp","ip","hashUserAgent","ua","signHmac","payload","secret","hashPassword","password","salt","hash","verifyPassword","stored","derived","signJwt","payload","secret","expiresInSeconds","now","header","body","sig","signHmac","h","sigEncoded","verifyJwt","token","parts","expected","sigBytes","actualHex","c","expectedBuf","actualBuf","exp","import_node_fs","import_node_path","import_node_url","DB_FILE_NAMES","_thisDir","importMetaUrl","isInsidePackageInstall","resolved","nodeModulesSegment","isInDist","resolveStoragePaths","rawPath","driver","basePath","ext","dbDir","profilesDir","logsDir","dbFileName","dbPath","tenants","profiles","consentRecordsBase","consentRecordsFull","consentHistory","visitors","usersBase","usersFull","roles","permissions","userRolesBase","userRolesFull","rolePermissions","auditLogs","apiKeys","cookieTemplates","uiTemplates","CORE_TABLES_SQLITE","CORE_TABLES_FULL","API_KEY_TABLES","TEMPLATE_TABLES","sqliteDef","def","buildColSQLite","c","type","parts","buildTableSQLite","t","lines","u","pgDef","buildColPg","buildTablePg","MYSQL_TEXT","mysqlDef","buildColMySQL","buildTableMySQL","toSQLite","tables","toPostgres","toMySQL","SCHEMA_SQL_SQLITE","SCHEMA_SQL_SQLITE_API_KEYS","SCHEMA_SQL_SQLITE_ENTERPRISE","SCHEMA_SQL_SQLITE_TEMPLATES","ALL_TABLES_FULL","SCHEMA_SQL_POSTGRES","SCHEMA_SQL_MYSQL","SEED_TENANT","SEED_PERMISSIONS","SEED_ROLES","adminExcluded","complianceAllowed","viewerAllowed","SEED_ROLE_PERMISSIONS","p","q","generateSeedSQL","id","name","slug","tenant","perms","rolesSQL","r","byRole","rp","rolePerms","roleId","permIds","pid","SEED_SQL","MAX_PAGE_SIZE","BetterSqlite3Adapter","config","sql","s","mod","dbPath","resolveStoragePaths","row","SCHEMA_SQL_SQLITE","SEED_SQL","SCHEMA_SQL_SQLITE_API_KEYS","SCHEMA_SQL_SQLITE_ENTERPRISE","SCHEMA_SQL_SQLITE_TEMPLATES","data","id","randomProfileId","now","profile","fields","vals","updated","tenantId","r","complianceGroup","histId","record","visitorId","existing","filters","conditions","limit","offset","rows","visitor","allowedTenants","allowedTenantsJson","user","email","roleId","permissionId","userId","pageSize","tc","gc","vc","totalConsents","recent","accepted","rejected","grantedPct","v","sample","stats","consent","key","status","days","total","detected","t","d","olderThanDays","cutoff","toDelete","visitor_id","keyHash","newName","src","name","settings","_n","settingsUpdate","merged","mainBanner","gpcBanner","preferenceModal","templateId","where","granted","denied","managed","byLocale","statuses","deniedPct","loc","dateRows","dateMap","entry","byDate","date","MAX_PAGE_SIZE","NodeSqlite3WasmAdapter","config","sql","s","mod","dbPath","resolveStoragePaths","stmt","ver","SCHEMA_SQL_SQLITE","SEED_SQL","SCHEMA_SQL_SQLITE_API_KEYS","SCHEMA_SQL_SQLITE_ENTERPRISE","SCHEMA_SQL_SQLITE_TEMPLATES","row","data","id","randomProfileId","now","profile","fields","vals","updated","tenantId","r","complianceGroup","p","histId","record","visitorId","existing","filters","conditions","limit","offset","rows","visitor","allowedTenants","allowedTenantsJson","user","email","roleId","permissionId","userId","pageSize","tc","gc","vc","totalConsents","recent","accepted","rejected","grantedPct","v","sample","stats","consent","key","status","days","total","detected","t","d","olderThanDays","cutoff","toDelete","visitor_id","keyHash","newName","src","name","settings","_n","settingsUpdate","merged","mainBanner","gpcBanner","preferenceModal","templateId","where","granted","denied","managed","byLocale","statuses","deniedPct","loc","dateRows","dateMap","entry","byDate","date","MAX_PAGE_SIZE","NodeSqliteBuiltinAdapter","config","sql","s","Db","dbPath","resolveStoragePaths","row","SCHEMA_SQL_SQLITE","SEED_SQL","SCHEMA_SQL_SQLITE_API_KEYS","SCHEMA_SQL_SQLITE_ENTERPRISE","SCHEMA_SQL_SQLITE_TEMPLATES","data","id","randomProfileId","now","profile","fields","vals","updated","tenantId","r","complianceGroup","histId","record","visitorId","existing","filters","conditions","limit","offset","rows","visitor","allowedTenants","allowedTenantsJson","user","email","roleId","permissionId","userId","pageSize","tc","gc","vc","totalConsents","recent","accepted","rejected","grantedPct","v","sample","stats","consent","key","status","days","total","detected","t","d","olderThanDays","cutoff","toDelete","visitor_id","keyHash","newName","src","name","settings","_n","settingsUpdate","merged","mainBanner","gpcBanner","preferenceModal","templateId","where","granted","denied","managed","byLocale","statuses","grantedCount","deniedCount","loc","dateRows","dateMap","entry","deniedPct","byDate","date","mapProfile","d","mapConsent","mapHistory","mapVisitor","mapUser","mapRole","mapPermission","mapAuditLog","MongoDBAdapter","config","name","MC","uri","id","slug","SEED_TENANT","p","SEED_PERMISSIONS","doc","r","SEED_ROLES","rp","roleId","permissionId","SEED_ROLE_PERMISSIONS","data","now","set","res","tenantId","complianceGroup","visitorId","existing","filters","q","page","limit","cursor","f","range","consentRecordId","oldJson","newJson","action","total","gpcCount","visitors","pipeline","results","granted","denied","all","rows","result","cookie","entry","days","from","email","ids","userId","filter","detected","keyHash","update","olderThanDays","cutoff","docs","visitorIds","mapProfile","r","mapConsent","mapHistory","mapVisitor","mapUser","mapRole","mapPermission","mapAuditLog","MySQLAdapter","config","sql","params","rows","result","mysql","cfg","conn","tables","stmt","SCHEMA_SQL_MYSQL","s","vrows","version","alters","SEED_TENANT","p","SEED_PERMISSIONS","SEED_ROLES","roleId","permissionId","SEED_ROLE_PERMISSIONS","data","id","row","sets","vals","tenantId","complianceGroup","visitorId","existing","filters","page","limit","f","consentRecordId","oldJson","newJson","action","countRow","gpcRow","visitorRow","total","gpcCount","visitors","statusRows","granted","denied","all","entry","days","from","email","userId","d","detected","keyHash","now","olderThanDays","cutoff","visitorRows","ids","placeholders","mapProfile","r","mapConsent","mapHistory","mapVisitor","mapUser","mapRole","mapPermission","mapAuditLog","PostgreSQLAdapter","config","sql","params","PgPool","cfg","poolCfg","client","version","stmt","SCHEMA_SQL_POSTGRES","s","err","alters","SEED_TENANT","p","SEED_PERMISSIONS","SEED_ROLES","roleId","permissionId","SEED_ROLE_PERMISSIONS","data","id","row","sets","vals","idx","rows","tenantId","complianceGroup","visitorId","existing","filters","nextIdx","page","limit","f","consentRecordId","oldJson","newJson","action","countRow","gpcRow","visitorRow","total","gpcCount","visitors","statusRows","granted","denied","all","result","entry","days","from","email","userId","d","detected","keyHash","now","olderThanDays","cutoff","visitorRows","ids","placeholders","_","i","import_promises","import_node_crypto","MAX_PAGE_SIZE","emptyDb","randomProfileId","page","arr","pageNum","limit","l","offset","JsonFileAdapter","config","tmp","err","dbPath","resolveStoragePaths","raw","now","id","name","slug","SEED_TENANT","t","p","SEED_PERMISSIONS","x","r","SEED_ROLES","rp","SEED_ROLE_PERMISSIONS","data","profile","idx","existing","updated","tenantId","a","b","complianceGroup","record","visitorId","c","h","filters","rows","visitor","v","user","u","ur","email","role","roleId","permIds","userId","urs","roleIds","permissionId","log","consents","recent","accepted","rejected","vals","grantedPct","sample","stats","key","status","days","cutoff","counts","date","count","consentVisitors","country","detected","total","tenant","olderThanDays","toDelete","keyHash","k","tpl","newName","src","settings","_name","mainBanner","gpcBanner","preferenceModal","json","ct","ut","templateId","records","granted","denied","managed","byLocale","dateMap","statuses","s","deniedPct","loc","entry","byDate","ProfileRepo","adapter","data","id","tenantId","complianceGroup","ConsentRepo","adapter","data","visitorId","filters","VisitorRepo","adapter","data","visitorId","AuditRepo","adapter","data","filters","UserRepo","adapter","id","email","tenantId","data","userId","roleId","mergeTranslations","base","override","resolveLocale","translations","requested","defaultLocale","exact","lang","langMatch","import_node_fs","import_node_path","import_node_worker_threads","import_node_url","import_node_path","import_node_fs","import_node_fs","import_node_path","import_node_crypto","sha256Hex","data","hmacSha256","key","toAmzDate","d","iso","getSigningKey","secretKey","dateStamp","region","service","kDate","kRegion","kService","buildSignedHeaders","params","method","body","contentType","config","now","amzDate","host","payloadHash","signedHeaderMap","sortedKeys","canonicalHeaders","k","signedHeadersList","canonicalRequest","credentialScope","stringToSign","signingKey","signature","authorization","s3Url","encodedKey","s3Put","headers","bodyStr","res","text","s3Delete","key","config","headers","buildSignedHeaders","res","s3Url","text","profilesRoot","storagePath","tenantId","versionDir","profileId","version","complianceDir","complianceGroup","s3Key","segment","locale","writeJsonFile","filePath","content","tmp","writeVersionDir","msg","profile","s3Config","dir","locales","defaultLocale","translations","s3Put","fallbackLocale","fallbackPath","activateComplianceGroup","srcDir","destDir","files","f","file","deactivateComplianceGroup","s3Delete","runWorkerAction","_dir","importMetaUrl","JS_WORKER","IS_DEV","runProfileJsonWrite","msg","runWorkerAction","resolve","reject","worker","result","err","buildTranslations","template","localeContents","result","locale","content","btn","i","cat","c","normaliseCookieLegalBasis","cookie","ProfileService","profiles","audit","tenantId","storage","eventBus","localeCache","profilesDir","handleCache","s3Config","profileId","complianceGroup","locales","dir","l","input","profile","resolved","paths","id","old","isActive","action","pj","updated","args","msg","runProfileJsonWrite","resolveLocale","currentLocale","cached","cookies","translations","ct","ut","localeKeys","response","versions","entries","entry","ver","vdir","f","createdAt","a","b","version","filePath","defaultPath","TIMEZONE_TO_COUNTRY","LANG_TO_COUNTRY","GeoResolverService","provider","map","ctx","country","region","regulation","locale","result","resolveFromTimezone","resolveFromLanguage","resolveFromGeoIPLite","resolveFromHosted","resolveFromMaxmind","geo","entry","language","parts","tag","timezone","TIMEZONE_TO_COUNTRY","ip","r","reg","maxmind","dbPath","resolve","https","url","req","res","chunks","c","body","import_node_fs","import_node_path","import_node_fs","import_node_path","safeJsonWrite","filePath","data","validateSchema","bak","tmp","had","parsed","err","isPublicProfileResponse","v","LocaleJsonCacheService","dir","profileId","locale","path","parsed","response","safeJsonWrite","responses","err","prefix","file","validateConsentInput","data","profile","errors","cookieId","status","cookie","c","buildConsentValue","cookies","submitted","gpcDetected","regulation","result","id","verifyConsent","record","reasons","isExpired","buildTcfPayload","consentValue","vendorSet","purposeSet","p","a","b","createdMs","now","expiryMs","encodeTcString","input","payload","ConsentService","consents","visitors","profiles","audit","tenantId","compliance","pluginEngine","eventBus","tcfConfig","input","profile","regulation","profileCookies","effectiveConsent","cookie","validation","validateConsentInput","builtConsent","buildConsentValue","tcfString","c","gvl","getGvl","vendorConsents","purposeConsents","buildTcfPayload","encodeTcString","baseInput","existing","record","updateData","visitorId","profileCookies2","effectiveGpc","verifyConsent","VisitorService","visitors","tenantId","eventBus","data","input","hashIp","hashUserAgent","visitor","UserService","users","audit","tenantId","user","_p","rest","input","actorId","hashPassword","id","existing","data","updated","u","userId","roleId","LOCKOUT_WINDOW_MS","MAX_FAILED_ATTEMPTS","LocalAuth","storage","secret","now","key","entry","email","password","passwordHash","hashPassword","user","attempts","verifyPassword","roles","permSets","r","permissions","p","signJwt","payload","token","verifyJwt","id","PayloadTooLargeError","getIp","req","trustedProxies","remoteIp","fwd","json","status","data","parseJsonBody","request","getQueryParam","url","key","getQueryInt","fallback","val","n","nodeRequestToFetch","maxBodyBytes","proto","host","headers","value","v","body","method","chunks","totalBytes","chunk","fetchResponseToNode","response","res","setCookies","cookie","reader","done","errorResponse","status","message","details","body","withErrorHandler","fn","err","import_node_fs","import_node_path","CACHE_CONTROL","JSON_HEADERS","serveJsonFile","filePath","content","redirectToDefault","basePath","tenantId","complianceGroup","buildProfileRoutes","profiles","geoResolver","profilesDir","_req","params","withErrorHandler","complianceGroupOrProfileId","locale","errorResponse","defaultPath","result","json","profileId","version","ver","request","_params","url","ip","timezone","language","requestedLocale","geo","profile","pj","availableLocales","resolvedLocale","warning","path","_request","id","buildCookieValue","consentJson","timestamp","entries","k","v","buildConsentSetCookie","record","name","value","secure","buildExpireSetCookie","visitorId","profileId","matchesAllowedOrigin","origin","allowedOrigins","hostname","pattern","suffix","buildCorsHeaders","allowOrigin","handleCors","request","withCors","response","cors","newHeaders","k","v","checkOriginAllowed","CSP","addSecurityHeaders","res","h","VALID_STATUSES","validateConsentJsonValues","consentJson","entries","key","val","validateCreateConsent","body","b","validateUpdateConsent","castCreateConsent","visitorId","tenantId","castUpdateConsent","result","assertVisitorOwnership","request","visitorId","cookieHeader","prefix","c","trimmed","errorResponse","buildConsentRoutes","consents","visitors","profiles","resolveTenantId","_params","withErrorHandler","body","parseJsonBody","validation","validateCreateConsent","b","profileId","profile","allowedOrigins","checkOriginAllowed","ip","ua","tenantId","input","castCreateConsent","record","setCookie","buildConsentSetCookie","params","ownershipError","validateUpdateConsent","castUpdateConsent","result","existing","headers","buildExpireSetCookie","import_node_crypto","authenticate","req","storage","config","secret","auth","token","payload","verifyJwt","sub","email","roles","permissions","allowedTenants","user","permSets","r","p","authError","permission","errorResponse","import_node_crypto","base64url","buf","base64urlDecode","generatePkce","verifier","challenge","discoverOidcEndpoints","issuer","res","buildAuthorizationUrl","config","authorizationEndpoint","state","nonce","codeChallenge","params","exchangeOidcCode","tokenEndpoint","code","codeVerifier","body","err","verifyOidcIdToken","idToken","jwksUri","parts","header","alg","jwks","jwk","k","cryptoKey","hashName","namedCurve","sigInput","padding","sigB64","sigBytes","c","verifyAlg","payload","now","extractEmailFromClaims","claims","mapping","key","value","extractRolesFromClaims","v","pendingStates","val","storePkceState","consumePkceState","entry","escXml","buildSamlMetadataXml","config","validateSamlResponse","samlResponse","samlify","sp","idp","result","email","rolesAttr","roles","r","err","import_node_crypto","BASE32_CHARS","base32Encode","buf","result","bits","value","byte","base32Decode","str","clean","bytes","char","idx","hotp","secret","counter","c","i","hmac","offset","code","generateTotpSecret","usedTokens","now","token","expiresAt","verifyTotp","secret","window","counter","secretBuf","base32Decode","tokenBuf","i","expected","hotp","totpQrUrl","email","issuer","label","params","base64url","buf","buildAdminAuthRoutes","localAuth","storage","authConfig","secret","authLimiter","checkAuthLimit","req","ip","errorResponse","_p","withErrorHandler","limited","body","parseJsonBody","b","token","json","user","authenticate","dbUser","roles","r","_req","endpoints","discoverOidcEndpoints","state","nonce","verifier","challenge","generatePkce","storePkceState","url","buildAuthorizationUrl","code","pkce","consumePkceState","tokens","exchangeOidcCode","claims","verifyOidcIdToken","email","extractEmailFromClaims","extractRolesFromClaims","allRoles","roleName","role","userRoles","permissions","perms","p","xml","buildSamlMetadataXml","samlResponse","info","validateSamlResponse","totpSecret","generateTotpSecret","qrUrl","totpQrUrl","verifyTotp","COMPLIANCE_GROUPS","COMPLIANCE_VALIDATION_RULES","c","id","EMBEDDED_COMPLIANCE_MAP","COUNTRY_CODES","acc","d","LOCALES","l","validateCreateProfile","body","b","pj","validateUpdateProfile","castCreateProfile","tenantId","castUpdateProfile","result","validateProfileCompliance","cookies","complianceGroup","rules","COMPLIANCE_VALIDATION_RULES","errors","warnings","cookie","c","rule","buildAdminProfileRoutes","service","storage","authConfig","secret","auth","req","perm","user","authenticate","authError","tenantAllowed","tenantId","_p","withErrorHandler","denied","json","p","profile","errorResponse","body","parseJsonBody","validateProfileCompliance","groups","groupId","groupDef","COMPLIANCE_GROUPS","validation","validateCreateProfile","input","castCreateProfile","complianceGroup","choice","cookies","complianceValidation","existing","id","validateUpdateProfile","castUpdateProfile","activated","locale","ver","content","buildAdminConsentRoutes","storage","authConfig","secret","auth","req","perm","user","authenticate","authError","_p","withErrorHandler","denied","json","url","profileId","getQueryParam","from","to","limit","getQueryInt","errorResponse","filters","records","p","record","history","buildAdminVisitorRoutes","storage","authConfig","secret","auth","req","perm","user","authenticate","authError","_p","withErrorHandler","denied","json","url","from","getQueryParam","to","limit","getQueryInt","errorResponse","filters","visitors","buildAdminUserRoutes","userService","storage","authConfig","secret","auth","req","perm","user","authenticate","authError","_p","withErrorHandler","denied","users","json","p","errorResponse","roles","r","actor","body","parseJsonBody","b","created","id","updated","tenantId","revokedTenantId","buildAdminRoleRoutes","storage","authConfig","secret","auth","req","perm","user","authenticate","authError","_p","withErrorHandler","denied","roles","json","p","perms","actor","body","parseJsonBody","errorResponse","b","role","buildAdminAuditRoutes","storage","authConfig","secret","auth","req","perm","user","authenticate","authError","_p","withErrorHandler","denied","json","url","action","getQueryParam","resourceType","from","to","limit","getQueryInt","errorResponse","filters","logs","buildAdminStatsRoutes","storage","authConfig","secret","auth","req","user","authenticate","authError","_p","withErrorHandler","denied","stats","json","url","days","getQueryInt","timeline","countries","gpc","tenants","rows","t","s","aggregate","acc","r","escapeCsv","val","s","consentToCsvRow","r","auditToCsvRow","buildAdminExportRoutes","storage","authConfig","secret","auth","req","user","authenticate","authError","_p","withErrorHandler","denied","url","format","getQueryParam","profileId","from","to","filters","records","enc","header","stream","controller","XlsxMod","rows","wb","ws","buf","p","profile","errorResponse","translations","locales","locale","t","section","content","field","value","logs","import_node_crypto","generateApiKey","raw","hash","buildAdminApiKeyRoutes","storage","authConfig","secret","auth","req","user","authenticate","authError","_p","withErrorHandler","denied","keys","json","k","body","created","p","buildAdminTenantRoutes","storage","authConfig","secret","auth","req","perm","user","authenticate","authError","_p","withErrorHandler","denied","tenants","json","body","parseJsonBody","errorResponse","b","tenant","p","id","buildAdminTcfRoutes","storage","authConfig","secret","auth","req","user","authenticate","authError","_p","withErrorHandler","denied","gvl","getGvl","json","url","search","page","limit","vendors","filtered","v","total","totalPages","safePage","start","buildAdminCookieTemplateRoutes","storage","authConfig","secret","tenantId","auth","req","perm","user","authenticate","authError","withErrorHandler","denied","json","params","t","errorResponse","body","parseJsonBody","id","update","oldTemplate","newCookieIds","c","removedIds","cid","profiles","blockingProfiles","p","validateProfileCompliance","src","newName","usage","buildAdminUITemplateRoutes","storage","authConfig","secret","tenantId","auth","req","perm","user","authenticate","authError","withErrorHandler","denied","json","params","t","errorResponse","body","parseJsonBody","update","id","profiles","p","src","newName","usage","buildAdminAnalyticsRoutes","storage","authConfig","secret","defaultTenantId","auth","req","perm","user","authenticate","authError","_p","withErrorHandler","denied","url","tenantId","filters","profileId","complianceGroup","from","to","locale","stats","json","import_node_crypto","resolveTenant","req","storage","defaultTenantId","auth","rawKey","keyHash","RateLimiter","windowMs","maxRequests","now","key","entry","ip","profileId","DIST_DIR","importMetaUrl","dashboardDir","MIME","tryServeDashboard","pathname","basePath","res","configScript","rel","target","raw","ext","isHtml","ct","injectConfigScript","serveDistFile","filePath","contentType","data","compilePath","path","paramNames","regexParts","part","branded404","html","buildFetchRouter","groups","rateLimiter","entries","group","key","handler","spaceIdx","method","pattern","request","corsResponse","handleCors","e","ip","withCors","errorResponse","entry","match","params","name","i","val","response","addSecurityHeaders","isUiPath","isPlainObj","v","deepMerge","base","override","result","ov","bv","DEFAULT_CONFIG","createStorageAdapter","config","MongoDBAdapter","MySQLAdapter","PostgreSQLAdapter","NodeSqliteBuiltinAdapter","BetterSqlite3Adapter","NodeSqlite3WasmAdapter","JsonFileAdapter","createConsenti","userConfig","storageConfig","authConfig","profilesDir","resolveStoragePaths","storage","eventBus","profileRepo","ProfileRepo","consentRepo","ConsentRepo","visitorRepo","VisitorRepo","auditRepo","AuditRepo","userRepo","UserRepo","pluginEngine","PluginEngine","compliance","complianceType","needsGeo","localeCache","LocaleJsonCacheService","geoResolver","GeoResolverService","EMBEDDED_COMPLIANCE_MAP","profileService","ProfileService","visitorService","VisitorService","consentService","ConsentService","userService","UserService","adminSecret","localAuth","LocalAuth","rl","RateLimiter","authLimiter","resolveTenantId","req","resolveTenant","_req","apiBase","adminBase","docsPath","dashboardEnabled","buildConsentiConfigScript","buildConsentiRuntimeConfig","swaggerHtml","robotsTxt","fetchRouter","OPENAPI_PUBLIC_SPEC","OPENAPI_ADMIN_SPEC","buildProfileRoutes","buildConsentRoutes","buildAdminAuthRoutes","buildAdminProfileRoutes","buildAdminConsentRoutes","buildAdminVisitorRoutes","buildAdminUserRoutes","buildAdminRoleRoutes","buildAdminAuditRoutes","buildAdminStatsRoutes","buildAdminExportRoutes","buildAdminApiKeyRoutes","buildAdminTenantRoutes","buildAdminTcfRoutes","buildAdminCookieTemplateRoutes","buildAdminUITemplateRoutes","buildAdminAnalyticsRoutes","retentionTimer","resolveReady","rejectReady","ready","rej","startGvlRefresh","days","purge","n","err","nodeHandler","proto","host","url","nodeRequestToFetch","fetchResponseToNode","PayloadTooLargeError","router","next","fastifyHandler","fastify","_opts","reply","body","stopGvlRefresh"]}
|