@xk2800/nextjs-template 0.7.1-beta.0 → 0.7.1-beta.10
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 +32 -30
- package/components/auth/deviceCheck.tsx +47 -6
- package/components/auth/oneTap.tsx +5 -5
- package/components/dashboard/admin/adminUserConsentCard.tsx +79 -0
- package/components/dashboard/admin/adminUserDevicesCard.tsx +80 -0
- package/components/dashboard/admin/broadcastActions.tsx +148 -0
- package/components/dashboard/admin/confirmSendDialog.tsx +44 -0
- package/components/dashboard/admin/marketingEmailForm.tsx +115 -0
- package/components/dashboard/admin/marketingSection.tsx +67 -0
- package/components/dashboard/admin/subscribersCard.tsx +62 -0
- package/components/dashboard/admin/systemSettingsForm.tsx +33 -0
- package/components/dashboard/admin/systemSettingsSection.tsx +8 -2
- package/components/dashboard/errorFeedback.tsx +2 -4
- package/components/dashboard/feedbackDialog.tsx +4 -4
- package/components/dashboard/marketingUpdatesCard.tsx +62 -0
- package/components/dashboard/marketingUpdatesSection.tsx +10 -0
- package/components/site/cookie-banner.tsx +109 -7
- package/components/ui/alert-dialog.tsx +1 -1
- package/components/ui/badge.tsx +1 -1
- package/components/ui/card.tsx +1 -1
- package/components/ui/data-table.tsx +4 -1
- package/components/ui/dialog.tsx +1 -1
- package/components/ui/dropdown-menu.tsx +2 -2
- package/components/ui/file-upload.tsx +129 -7
- package/components/ui/select.tsx +189 -0
- package/components/ui/switch.tsx +2 -2
- package/dist/activity/logger.js +36 -0
- package/dist/activity/logger.js.map +1 -1
- package/dist/activity/logger.mjs +4 -4
- package/dist/activity/queries.d.mts +1 -1
- package/dist/activity/queries.d.ts +1 -1
- package/dist/activity/queries.js +36 -0
- package/dist/activity/queries.js.map +1 -1
- package/dist/activity/queries.mjs +3 -3
- package/dist/admin/queries.d.mts +19 -1
- package/dist/admin/queries.d.ts +19 -1
- package/dist/admin/queries.js +64 -0
- package/dist/admin/queries.js.map +1 -1
- package/dist/admin/queries.mjs +26 -5
- package/dist/admin/queries.mjs.map +1 -1
- package/dist/api/feedback.js +53 -2
- package/dist/api/feedback.js.map +1 -1
- package/dist/api/feedback.mjs +9 -8
- package/dist/api/feedback.mjs.map +1 -1
- package/dist/api/marketing.d.mts +36 -0
- package/dist/api/marketing.d.ts +36 -0
- package/dist/api/marketing.js +1357 -0
- package/dist/api/marketing.js.map +1 -0
- package/dist/api/marketing.mjs +170 -0
- package/dist/api/marketing.mjs.map +1 -0
- package/dist/auth/helpers.js +51 -0
- package/dist/auth/helpers.js.map +1 -1
- package/dist/auth/helpers.mjs +9 -64
- package/dist/auth/helpers.mjs.map +1 -1
- package/dist/auth/index.d.mts +2 -2
- package/dist/auth/index.d.ts +2 -2
- package/dist/auth/index.js +51 -0
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/index.mjs +8 -7
- package/dist/{chunk-KAEA35OC.mjs → chunk-6MDQRT6U.mjs} +4 -4
- package/dist/{chunk-KAEA35OC.mjs.map → chunk-6MDQRT6U.mjs.map} +1 -1
- package/dist/{chunk-N6ECRCHY.mjs → chunk-6OAHCEDJ.mjs} +4 -3
- package/dist/chunk-6OAHCEDJ.mjs.map +1 -0
- package/dist/chunk-6Z3WUSDJ.mjs +62 -0
- package/dist/chunk-6Z3WUSDJ.mjs.map +1 -0
- package/dist/{chunk-VQ5B4MA7.mjs → chunk-7F2POZM6.mjs} +4 -4
- package/dist/{chunk-VQ5B4MA7.mjs.map → chunk-7F2POZM6.mjs.map} +1 -1
- package/dist/{chunk-XWVAJXAG.mjs → chunk-7QVIOQ47.mjs} +23 -19
- package/dist/chunk-7QVIOQ47.mjs.map +1 -0
- package/dist/chunk-C6RGN6QA.mjs +60 -0
- package/dist/chunk-C6RGN6QA.mjs.map +1 -0
- package/dist/chunk-OVKVD2HH.mjs +25 -0
- package/dist/chunk-OVKVD2HH.mjs.map +1 -0
- package/dist/{chunk-3MGEAGHU.mjs → chunk-P2G23JMY.mjs} +11 -6
- package/dist/chunk-P2G23JMY.mjs.map +1 -0
- package/dist/{chunk-TMJYAOC2.mjs → chunk-TKWNEKK6.mjs} +8 -2
- package/dist/chunk-TKWNEKK6.mjs.map +1 -0
- package/dist/{chunk-ZQCALTKB.mjs → chunk-TR5XFBTD.mjs} +34 -4
- package/dist/chunk-TR5XFBTD.mjs.map +1 -0
- package/dist/{chunk-WZDAMCUX.mjs → chunk-ZJMFE5B2.mjs} +4 -4
- package/dist/{chunk-WZDAMCUX.mjs.map → chunk-ZJMFE5B2.mjs.map} +1 -1
- package/dist/config/env.d.mts +2 -0
- package/dist/config/env.d.ts +2 -0
- package/dist/config/env.js +6 -0
- package/dist/config/env.js.map +1 -1
- package/dist/config/env.mjs +1 -1
- package/dist/db/index.d.mts +1 -1
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.js +36 -0
- package/dist/db/index.js.map +1 -1
- package/dist/db/index.mjs +3 -3
- package/dist/db/schema.d.mts +1 -1
- package/dist/db/schema.d.ts +1 -1
- package/dist/db/schema.js +30 -0
- package/dist/db/schema.js.map +1 -1
- package/dist/db/schema.mjs +1 -1
- package/dist/errors.js +36 -0
- package/dist/errors.js.map +1 -1
- package/dist/errors.mjs +4 -4
- package/dist/marketing/index.d.mts +35 -0
- package/dist/marketing/index.d.ts +35 -0
- package/dist/marketing/index.js +125 -0
- package/dist/marketing/index.js.map +1 -0
- package/dist/marketing/index.mjs +6 -0
- package/dist/marketing/index.mjs.map +1 -0
- package/dist/{schema-BNSBWNjK.d.mts → schema-CN_Y6EXv.d.mts} +149 -3
- package/dist/{schema-BNSBWNjK.d.ts → schema-CN_Y6EXv.d.ts} +149 -3
- package/dist/sessions/queries.js +36 -0
- package/dist/sessions/queries.js.map +1 -1
- package/dist/sessions/queries.mjs +3 -3
- package/dist/settings/queries.d.mts +4 -3
- package/dist/settings/queries.d.ts +4 -3
- package/dist/settings/queries.js +42 -0
- package/dist/settings/queries.js.map +1 -1
- package/dist/settings/queries.mjs +4 -4
- package/dist/users/queries.js +36 -0
- package/dist/users/queries.js.map +1 -1
- package/dist/users/queries.mjs +3 -3
- package/lib/cookie-consent.ts +72 -20
- package/lib/cookie-names.ts +47 -0
- package/lib/device-fingerprint.ts +66 -10
- package/lib/recalculate-columns.ts +2 -0
- package/package.json +28 -3
- package/styles/theme.css +17 -3
- package/dist/chunk-3MGEAGHU.mjs.map +0 -1
- package/dist/chunk-N6ECRCHY.mjs.map +0 -1
- package/dist/chunk-TMJYAOC2.mjs.map +0 -1
- package/dist/chunk-XWVAJXAG.mjs.map +0 -1
- package/dist/chunk-ZQCALTKB.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../config/env-schema.ts","../../config/env.ts","../../lib/resend.ts","../../lib/marketing.ts"],"names":["z","error"],"mappings":"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","file":"index.js","sourcesContent":["// No \"server-only\" guard here — this schema is also imported by scripts that\n// run outside Next.js's bundler (e.g. scripts/doctor.ts), where that guard\n// throws unconditionally. config/env.ts re-exports the parsed, guarded result\n// for app code; import this file directly only from non-Next scripts.\nimport { z } from 'zod';\n\nexport const envSchema = z.object({\n NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),\n PORT: z.string().default('3000').transform(Number),\n DATABASE_URL: z.string().default(''),\n RESEND_API_KEY: z.string().default(''),\n // Full access key for marketing broadcasts (admin Marketing email page).\n // Blank = use RESEND_API_KEY.\n RESEND_BROADCAST_API_KEY: z.string().default(''),\n // Resend segment users join from the dashboard \"Email updates\" toggle.\n // Blank = toggle hidden.\n RESEND_MARKETING_SEGMENT_ID: z.string().default(''),\n // Sender for every transactional email. Must be on a domain verified in\n // your Resend account.\n EMAIL_FROM: z.string().default('Acme <onboarding@xavierkhew.xyz>'),\n // Display name for this deployment — shown as the authenticator-app label\n // (2FA issuer) and the passkey relying-party name. Consuming projects set\n // this in their own .env; defaults to the template name.\n APP_NAME: z.string().default('Next.js Template'),\n // Where the dashboard feedback form delivers (app/api/feedback). Set either\n // or both; with neither, the Feedback button is hidden. FEEDBACK_EMAIL takes\n // a comma-separated list and sends through Resend (needs RESEND_API_KEY).\n FEEDBACK_DISCORD_WEBHOOK_URL: z.string().default(''),\n FEEDBACK_EMAIL: z.string().default(''),\n // Seed-only: the live value lives in the system_settings DB row (see\n // lib/settings-queries.ts) once it's been seeded on first read, and is\n // changed from the admin System Settings page, not by editing this var.\n ENABLE_SESSION_REVOCATION: z.string().default('true').transform(val => val === 'true'),\n AUTH_ENABLE_GOOGLE: z.string().default('true').transform(val => val === 'true'),\n AUTH_ENABLE_EMAIL_PASSWORD: z.string().default('true').transform(val => val === 'true'),\n AUTH_ENABLE_ONE_TAP: z.string().default('false').transform(val => val === 'true'),\n DB_DRIVER: z.enum(['pg', 'neon']).default('pg'),\n // Only relevant when DB_DRIVER=pg — whether the target Postgres server has SSL\n // enabled. Self-hosted Postgres (e.g. via Docker/Dokploy) typically does not.\n DATABASE_SSL: z.string().default('false').transform(val => val === 'true'),\n});\n","import \"server-only\";\nimport { envSchema } from './env-schema';\n\nconst results = envSchema.safeParse(process.env);\n\nif (results.success && (results.data.NODE_ENV === 'development')) {\n console.log('Environment variables loaded:', Object.keys(results.data));\n}\n\nif (!results.success) {\n console.error('Invalid environment variables:', results.error.format());\n throw new Error('Invalid environment variables');\n}\n\nexport const config = results.data;\n","import \"server-only\"\nimport type { Resend } from \"resend\"\nimport { config } from \"@/config/env\"\n\n// From env, not hardcoded: scaffolded apps run this module from the package's\n// bundled auth, so a local edit here would never reach their auth emails.\nexport const EMAIL_FROM = config.EMAIL_FROM\n\n// Loaded on first send, so projects that never send email don't pay for it\n// at startup.\nlet resend: Resend | undefined\nexport async function getResend() {\n if (!resend) {\n const { Resend } = await import(\"resend\")\n resend = new Resend(config.RESEND_API_KEY)\n }\n return resend\n}\n\n// Broadcasts need a full access key, so they can use their own and leave\n// RESEND_API_KEY as a sending-only key.\nexport const BROADCAST_API_KEY = config.RESEND_BROADCAST_API_KEY || config.RESEND_API_KEY\n\nlet broadcastResend: Resend | undefined\nexport async function getBroadcastResend() {\n if (!broadcastResend) {\n const { Resend } = await import(\"resend\")\n broadcastResend = new Resend(BROADCAST_API_KEY)\n }\n return broadcastResend\n}\n","import \"server-only\"\n// Marketing email data helpers, shipped as `@xk2800/nextjs-template/marketing`.\n// Everything goes through Resend Broadcasts/Contacts with the broadcast key,\n// so it never touches the transactional sending quota.\nimport { config } from \"../config/env\"\nimport { getBroadcastResend, BROADCAST_API_KEY } from \"./resend\"\n\n// The segment users join from the dashboard toggle. Blank = toggle hidden.\nexport const MARKETING_SEGMENT_ID = config.RESEND_MARKETING_SEGMENT_ID\n\nexport interface MarketingSegment {\n id: string\n name: string\n}\n\nexport interface MarketingBroadcast {\n id: string\n name: string | null\n status: string\n created_at: string\n sent_at: string | null\n}\n\nexport interface MarketingContact {\n id: string\n email: string\n first_name?: string\n last_name?: string\n unsubscribed: boolean\n created_at: string\n}\n\n// Segments + the 10 latest broadcasts for the admin page. `error` is set\n// instead of throwing, so the page can explain a missing or sending-only key.\nexport async function getMarketingOverview(): Promise<{\n segments: MarketingSegment[]\n broadcasts: MarketingBroadcast[]\n error: string | null\n}> {\n if (!BROADCAST_API_KEY) {\n return { segments: [], broadcasts: [], error: \"Neither RESEND_BROADCAST_API_KEY nor RESEND_API_KEY is set.\" }\n }\n\n const resend = await getBroadcastResend()\n const [segRes, bcRes] = await Promise.all([\n resend.segments.list(),\n resend.broadcasts.list({ limit: 10 }),\n ])\n if (segRes.error) return { segments: [], broadcasts: [], error: segRes.error.message }\n return { segments: segRes.data.data, broadcasts: bcRes.data?.data ?? [], error: null }\n}\n\n// ponytail: first page only (Resend max 100); add cursor paging (`after`)\n// if a segment outgrows it.\nexport const SEGMENT_CONTACTS_LIMIT = 100\n\nexport async function listSegmentContacts(segmentId: string): Promise<{\n contacts: MarketingContact[]\n hasMore: boolean\n error: string | null\n}> {\n const { data, error } = await (await getBroadcastResend()).contacts.list({ segmentId, limit: SEGMENT_CONTACTS_LIMIT })\n if (error) return { contacts: [], hasMore: false, error: error.message }\n return { contacts: data.data, hasMore: data.has_more, error: null }\n}\n\n// Resend is the source of truth, so the toggle also reflects someone who\n// clicked Unsubscribe in an email or was edited in the Resend dashboard.\nexport async function isSubscribed(email: string): Promise<boolean> {\n const resend = await getBroadcastResend()\n const contact = await resend.contacts.get({ email })\n if (contact.error) {\n if (contact.error.name === \"not_found\") return false\n throw new Error(contact.error.message)\n }\n if (contact.data.unsubscribed) return false\n\n const segments = await resend.contacts.segments.list({ email })\n if (segments.error) throw new Error(segments.error.message)\n return segments.data.data.some((s) => s.id === MARKETING_SEGMENT_ID)\n}\n\nexport async function setSubscribed(email: string, name: string, subscribed: boolean) {\n const resend = await getBroadcastResend()\n const contact = await resend.contacts.get({ email })\n const exists = !contact.error\n if (contact.error && contact.error.name !== \"not_found\") throw new Error(contact.error.message)\n\n if (!subscribed) {\n // Same as the email's Unsubscribe link: opted out of every broadcast.\n if (!exists) return\n const { error } = await resend.contacts.update({ email, unsubscribed: true })\n if (error) throw new Error(error.message)\n return\n }\n\n const { error } = exists\n ? await resend.contacts.update({ email, unsubscribed: false })\n : await resend.contacts.create({ email, firstName: name || undefined, unsubscribed: false })\n if (error) throw new Error(error.message)\n\n const segments = await resend.contacts.segments.list({ email })\n if (segments.error) throw new Error(segments.error.message)\n if (!segments.data.data.some((s) => s.id === MARKETING_SEGMENT_ID)) {\n const added = await resend.contacts.segments.add({ email, segmentId: MARKETING_SEGMENT_ID })\n if (added.error) throw new Error(added.error.message)\n }\n}\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { MARKETING_SEGMENT_ID, SEGMENT_CONTACTS_LIMIT, getMarketingOverview, isSubscribed, listSegmentContacts, setSubscribed } from '../chunk-C6RGN6QA.mjs';
|
|
2
|
+
import '../chunk-OVKVD2HH.mjs';
|
|
3
|
+
import '../chunk-TKWNEKK6.mjs';
|
|
4
|
+
import '../chunk-3465SI5N.mjs';
|
|
5
|
+
//# sourceMappingURL=index.mjs.map
|
|
6
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.mjs"}
|
|
@@ -1142,7 +1142,7 @@ declare const activityLogs: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
1142
1142
|
tableName: "activity_log";
|
|
1143
1143
|
dataType: "string";
|
|
1144
1144
|
columnType: "PgEnumColumn";
|
|
1145
|
-
data: "
|
|
1145
|
+
data: "login" | "logout" | "login_failed" | "password_changed" | "email_changed" | "profile_updated" | "session_revoked" | "user_deleted" | "user_banned" | "user_unbanned" | "role_changed" | "impersonation_started" | "impersonation_stopped" | "settings_changed" | "passkey_added" | "passkey_removed";
|
|
1146
1146
|
driverParam: string;
|
|
1147
1147
|
notNull: true;
|
|
1148
1148
|
hasDefault: false;
|
|
@@ -1467,6 +1467,25 @@ declare const deviceFingerprints: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
1467
1467
|
identity: undefined;
|
|
1468
1468
|
generated: undefined;
|
|
1469
1469
|
}, {}, {}>;
|
|
1470
|
+
components: drizzle_orm_pg_core.PgColumn<{
|
|
1471
|
+
name: "components";
|
|
1472
|
+
tableName: "device_fingerprint";
|
|
1473
|
+
dataType: "json";
|
|
1474
|
+
columnType: "PgJsonb";
|
|
1475
|
+
data: Record<string, unknown>;
|
|
1476
|
+
driverParam: unknown;
|
|
1477
|
+
notNull: false;
|
|
1478
|
+
hasDefault: false;
|
|
1479
|
+
isPrimaryKey: false;
|
|
1480
|
+
isAutoincrement: false;
|
|
1481
|
+
hasRuntimeDefault: false;
|
|
1482
|
+
enumValues: undefined;
|
|
1483
|
+
baseColumn: never;
|
|
1484
|
+
identity: undefined;
|
|
1485
|
+
generated: undefined;
|
|
1486
|
+
}, {}, {
|
|
1487
|
+
$type: Record<string, unknown>;
|
|
1488
|
+
}>;
|
|
1470
1489
|
createdAt: drizzle_orm_pg_core.PgColumn<{
|
|
1471
1490
|
name: "createdAt";
|
|
1472
1491
|
tableName: "device_fingerprint";
|
|
@@ -1487,6 +1506,115 @@ declare const deviceFingerprints: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
1487
1506
|
};
|
|
1488
1507
|
dialect: "pg";
|
|
1489
1508
|
}>;
|
|
1509
|
+
declare const consentLog: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
1510
|
+
name: "consent_log";
|
|
1511
|
+
schema: undefined;
|
|
1512
|
+
columns: {
|
|
1513
|
+
id: drizzle_orm_pg_core.PgColumn<{
|
|
1514
|
+
name: "id";
|
|
1515
|
+
tableName: "consent_log";
|
|
1516
|
+
dataType: "string";
|
|
1517
|
+
columnType: "PgText";
|
|
1518
|
+
data: string;
|
|
1519
|
+
driverParam: string;
|
|
1520
|
+
notNull: true;
|
|
1521
|
+
hasDefault: true;
|
|
1522
|
+
isPrimaryKey: true;
|
|
1523
|
+
isAutoincrement: false;
|
|
1524
|
+
hasRuntimeDefault: true;
|
|
1525
|
+
enumValues: [string, ...string[]];
|
|
1526
|
+
baseColumn: never;
|
|
1527
|
+
identity: undefined;
|
|
1528
|
+
generated: undefined;
|
|
1529
|
+
}, {}, {}>;
|
|
1530
|
+
userId: drizzle_orm_pg_core.PgColumn<{
|
|
1531
|
+
name: "userId";
|
|
1532
|
+
tableName: "consent_log";
|
|
1533
|
+
dataType: "string";
|
|
1534
|
+
columnType: "PgText";
|
|
1535
|
+
data: string;
|
|
1536
|
+
driverParam: string;
|
|
1537
|
+
notNull: true;
|
|
1538
|
+
hasDefault: false;
|
|
1539
|
+
isPrimaryKey: false;
|
|
1540
|
+
isAutoincrement: false;
|
|
1541
|
+
hasRuntimeDefault: false;
|
|
1542
|
+
enumValues: [string, ...string[]];
|
|
1543
|
+
baseColumn: never;
|
|
1544
|
+
identity: undefined;
|
|
1545
|
+
generated: undefined;
|
|
1546
|
+
}, {}, {}>;
|
|
1547
|
+
choice: drizzle_orm_pg_core.PgColumn<{
|
|
1548
|
+
name: "choice";
|
|
1549
|
+
tableName: "consent_log";
|
|
1550
|
+
dataType: "string";
|
|
1551
|
+
columnType: "PgText";
|
|
1552
|
+
data: string;
|
|
1553
|
+
driverParam: string;
|
|
1554
|
+
notNull: true;
|
|
1555
|
+
hasDefault: false;
|
|
1556
|
+
isPrimaryKey: false;
|
|
1557
|
+
isAutoincrement: false;
|
|
1558
|
+
hasRuntimeDefault: false;
|
|
1559
|
+
enumValues: [string, ...string[]];
|
|
1560
|
+
baseColumn: never;
|
|
1561
|
+
identity: undefined;
|
|
1562
|
+
generated: undefined;
|
|
1563
|
+
}, {}, {}>;
|
|
1564
|
+
version: drizzle_orm_pg_core.PgColumn<{
|
|
1565
|
+
name: "version";
|
|
1566
|
+
tableName: "consent_log";
|
|
1567
|
+
dataType: "number";
|
|
1568
|
+
columnType: "PgInteger";
|
|
1569
|
+
data: number;
|
|
1570
|
+
driverParam: string | number;
|
|
1571
|
+
notNull: true;
|
|
1572
|
+
hasDefault: false;
|
|
1573
|
+
isPrimaryKey: false;
|
|
1574
|
+
isAutoincrement: false;
|
|
1575
|
+
hasRuntimeDefault: false;
|
|
1576
|
+
enumValues: undefined;
|
|
1577
|
+
baseColumn: never;
|
|
1578
|
+
identity: undefined;
|
|
1579
|
+
generated: undefined;
|
|
1580
|
+
}, {}, {}>;
|
|
1581
|
+
previousId: drizzle_orm_pg_core.PgColumn<{
|
|
1582
|
+
name: "previousId";
|
|
1583
|
+
tableName: "consent_log";
|
|
1584
|
+
dataType: "string";
|
|
1585
|
+
columnType: "PgText";
|
|
1586
|
+
data: string;
|
|
1587
|
+
driverParam: string;
|
|
1588
|
+
notNull: false;
|
|
1589
|
+
hasDefault: false;
|
|
1590
|
+
isPrimaryKey: false;
|
|
1591
|
+
isAutoincrement: false;
|
|
1592
|
+
hasRuntimeDefault: false;
|
|
1593
|
+
enumValues: [string, ...string[]];
|
|
1594
|
+
baseColumn: never;
|
|
1595
|
+
identity: undefined;
|
|
1596
|
+
generated: undefined;
|
|
1597
|
+
}, {}, {}>;
|
|
1598
|
+
createdAt: drizzle_orm_pg_core.PgColumn<{
|
|
1599
|
+
name: "createdAt";
|
|
1600
|
+
tableName: "consent_log";
|
|
1601
|
+
dataType: "date";
|
|
1602
|
+
columnType: "PgTimestamp";
|
|
1603
|
+
data: Date;
|
|
1604
|
+
driverParam: string;
|
|
1605
|
+
notNull: true;
|
|
1606
|
+
hasDefault: true;
|
|
1607
|
+
isPrimaryKey: false;
|
|
1608
|
+
isAutoincrement: false;
|
|
1609
|
+
hasRuntimeDefault: false;
|
|
1610
|
+
enumValues: undefined;
|
|
1611
|
+
baseColumn: never;
|
|
1612
|
+
identity: undefined;
|
|
1613
|
+
generated: undefined;
|
|
1614
|
+
}, {}, {}>;
|
|
1615
|
+
};
|
|
1616
|
+
dialect: "pg";
|
|
1617
|
+
}>;
|
|
1490
1618
|
declare const authThrottle: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
1491
1619
|
name: "auth_throttle";
|
|
1492
1620
|
schema: undefined;
|
|
@@ -1813,6 +1941,23 @@ declare const systemSettings: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
1813
1941
|
identity: undefined;
|
|
1814
1942
|
generated: undefined;
|
|
1815
1943
|
}, {}, {}>;
|
|
1944
|
+
consentRequired: drizzle_orm_pg_core.PgColumn<{
|
|
1945
|
+
name: "consentRequired";
|
|
1946
|
+
tableName: "system_settings";
|
|
1947
|
+
dataType: "boolean";
|
|
1948
|
+
columnType: "PgBoolean";
|
|
1949
|
+
data: boolean;
|
|
1950
|
+
driverParam: boolean;
|
|
1951
|
+
notNull: false;
|
|
1952
|
+
hasDefault: false;
|
|
1953
|
+
isPrimaryKey: false;
|
|
1954
|
+
isAutoincrement: false;
|
|
1955
|
+
hasRuntimeDefault: false;
|
|
1956
|
+
enumValues: undefined;
|
|
1957
|
+
baseColumn: never;
|
|
1958
|
+
identity: undefined;
|
|
1959
|
+
generated: undefined;
|
|
1960
|
+
}, {}, {}>;
|
|
1816
1961
|
updatedAt: drizzle_orm_pg_core.PgColumn<{
|
|
1817
1962
|
name: "updatedAt";
|
|
1818
1963
|
tableName: "system_settings";
|
|
@@ -1931,6 +2076,7 @@ declare const schema_RoleEnum: typeof RoleEnum;
|
|
|
1931
2076
|
declare const schema_accounts: typeof accounts;
|
|
1932
2077
|
declare const schema_activityLogs: typeof activityLogs;
|
|
1933
2078
|
declare const schema_authThrottle: typeof authThrottle;
|
|
2079
|
+
declare const schema_consentLog: typeof consentLog;
|
|
1934
2080
|
declare const schema_deviceFingerprints: typeof deviceFingerprints;
|
|
1935
2081
|
declare const schema_errorRefs: typeof errorRefs;
|
|
1936
2082
|
declare const schema_passkeys: typeof passkeys;
|
|
@@ -1940,7 +2086,7 @@ declare const schema_twoFactors: typeof twoFactors;
|
|
|
1940
2086
|
declare const schema_users: typeof users;
|
|
1941
2087
|
declare const schema_verifications: typeof verifications;
|
|
1942
2088
|
declare namespace schema {
|
|
1943
|
-
export { schema_ActivityActionEnum as ActivityActionEnum, schema_RoleEnum as RoleEnum, schema_accounts as accounts, schema_activityLogs as activityLogs, schema_authThrottle as authThrottle, schema_deviceFingerprints as deviceFingerprints, schema_errorRefs as errorRefs, schema_passkeys as passkeys, schema_sessions as sessions, schema_systemSettings as systemSettings, schema_twoFactors as twoFactors, schema_users as users, schema_verifications as verifications };
|
|
2089
|
+
export { schema_ActivityActionEnum as ActivityActionEnum, schema_RoleEnum as RoleEnum, schema_accounts as accounts, schema_activityLogs as activityLogs, schema_authThrottle as authThrottle, schema_consentLog as consentLog, schema_deviceFingerprints as deviceFingerprints, schema_errorRefs as errorRefs, schema_passkeys as passkeys, schema_sessions as sessions, schema_systemSettings as systemSettings, schema_twoFactors as twoFactors, schema_users as users, schema_verifications as verifications };
|
|
1944
2090
|
}
|
|
1945
2091
|
|
|
1946
|
-
export { ActivityActionEnum as A, RoleEnum as R, schema as a, accounts as b, activityLogs as c, authThrottle as d,
|
|
2092
|
+
export { ActivityActionEnum as A, RoleEnum as R, schema as a, accounts as b, activityLogs as c, authThrottle as d, consentLog as e, deviceFingerprints as f, errorRefs as g, sessions as h, passkeys as p, systemSettings as s, twoFactors as t, users as u, verifications as v };
|
|
@@ -1142,7 +1142,7 @@ declare const activityLogs: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
1142
1142
|
tableName: "activity_log";
|
|
1143
1143
|
dataType: "string";
|
|
1144
1144
|
columnType: "PgEnumColumn";
|
|
1145
|
-
data: "
|
|
1145
|
+
data: "login" | "logout" | "login_failed" | "password_changed" | "email_changed" | "profile_updated" | "session_revoked" | "user_deleted" | "user_banned" | "user_unbanned" | "role_changed" | "impersonation_started" | "impersonation_stopped" | "settings_changed" | "passkey_added" | "passkey_removed";
|
|
1146
1146
|
driverParam: string;
|
|
1147
1147
|
notNull: true;
|
|
1148
1148
|
hasDefault: false;
|
|
@@ -1467,6 +1467,25 @@ declare const deviceFingerprints: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
1467
1467
|
identity: undefined;
|
|
1468
1468
|
generated: undefined;
|
|
1469
1469
|
}, {}, {}>;
|
|
1470
|
+
components: drizzle_orm_pg_core.PgColumn<{
|
|
1471
|
+
name: "components";
|
|
1472
|
+
tableName: "device_fingerprint";
|
|
1473
|
+
dataType: "json";
|
|
1474
|
+
columnType: "PgJsonb";
|
|
1475
|
+
data: Record<string, unknown>;
|
|
1476
|
+
driverParam: unknown;
|
|
1477
|
+
notNull: false;
|
|
1478
|
+
hasDefault: false;
|
|
1479
|
+
isPrimaryKey: false;
|
|
1480
|
+
isAutoincrement: false;
|
|
1481
|
+
hasRuntimeDefault: false;
|
|
1482
|
+
enumValues: undefined;
|
|
1483
|
+
baseColumn: never;
|
|
1484
|
+
identity: undefined;
|
|
1485
|
+
generated: undefined;
|
|
1486
|
+
}, {}, {
|
|
1487
|
+
$type: Record<string, unknown>;
|
|
1488
|
+
}>;
|
|
1470
1489
|
createdAt: drizzle_orm_pg_core.PgColumn<{
|
|
1471
1490
|
name: "createdAt";
|
|
1472
1491
|
tableName: "device_fingerprint";
|
|
@@ -1487,6 +1506,115 @@ declare const deviceFingerprints: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
1487
1506
|
};
|
|
1488
1507
|
dialect: "pg";
|
|
1489
1508
|
}>;
|
|
1509
|
+
declare const consentLog: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
1510
|
+
name: "consent_log";
|
|
1511
|
+
schema: undefined;
|
|
1512
|
+
columns: {
|
|
1513
|
+
id: drizzle_orm_pg_core.PgColumn<{
|
|
1514
|
+
name: "id";
|
|
1515
|
+
tableName: "consent_log";
|
|
1516
|
+
dataType: "string";
|
|
1517
|
+
columnType: "PgText";
|
|
1518
|
+
data: string;
|
|
1519
|
+
driverParam: string;
|
|
1520
|
+
notNull: true;
|
|
1521
|
+
hasDefault: true;
|
|
1522
|
+
isPrimaryKey: true;
|
|
1523
|
+
isAutoincrement: false;
|
|
1524
|
+
hasRuntimeDefault: true;
|
|
1525
|
+
enumValues: [string, ...string[]];
|
|
1526
|
+
baseColumn: never;
|
|
1527
|
+
identity: undefined;
|
|
1528
|
+
generated: undefined;
|
|
1529
|
+
}, {}, {}>;
|
|
1530
|
+
userId: drizzle_orm_pg_core.PgColumn<{
|
|
1531
|
+
name: "userId";
|
|
1532
|
+
tableName: "consent_log";
|
|
1533
|
+
dataType: "string";
|
|
1534
|
+
columnType: "PgText";
|
|
1535
|
+
data: string;
|
|
1536
|
+
driverParam: string;
|
|
1537
|
+
notNull: true;
|
|
1538
|
+
hasDefault: false;
|
|
1539
|
+
isPrimaryKey: false;
|
|
1540
|
+
isAutoincrement: false;
|
|
1541
|
+
hasRuntimeDefault: false;
|
|
1542
|
+
enumValues: [string, ...string[]];
|
|
1543
|
+
baseColumn: never;
|
|
1544
|
+
identity: undefined;
|
|
1545
|
+
generated: undefined;
|
|
1546
|
+
}, {}, {}>;
|
|
1547
|
+
choice: drizzle_orm_pg_core.PgColumn<{
|
|
1548
|
+
name: "choice";
|
|
1549
|
+
tableName: "consent_log";
|
|
1550
|
+
dataType: "string";
|
|
1551
|
+
columnType: "PgText";
|
|
1552
|
+
data: string;
|
|
1553
|
+
driverParam: string;
|
|
1554
|
+
notNull: true;
|
|
1555
|
+
hasDefault: false;
|
|
1556
|
+
isPrimaryKey: false;
|
|
1557
|
+
isAutoincrement: false;
|
|
1558
|
+
hasRuntimeDefault: false;
|
|
1559
|
+
enumValues: [string, ...string[]];
|
|
1560
|
+
baseColumn: never;
|
|
1561
|
+
identity: undefined;
|
|
1562
|
+
generated: undefined;
|
|
1563
|
+
}, {}, {}>;
|
|
1564
|
+
version: drizzle_orm_pg_core.PgColumn<{
|
|
1565
|
+
name: "version";
|
|
1566
|
+
tableName: "consent_log";
|
|
1567
|
+
dataType: "number";
|
|
1568
|
+
columnType: "PgInteger";
|
|
1569
|
+
data: number;
|
|
1570
|
+
driverParam: string | number;
|
|
1571
|
+
notNull: true;
|
|
1572
|
+
hasDefault: false;
|
|
1573
|
+
isPrimaryKey: false;
|
|
1574
|
+
isAutoincrement: false;
|
|
1575
|
+
hasRuntimeDefault: false;
|
|
1576
|
+
enumValues: undefined;
|
|
1577
|
+
baseColumn: never;
|
|
1578
|
+
identity: undefined;
|
|
1579
|
+
generated: undefined;
|
|
1580
|
+
}, {}, {}>;
|
|
1581
|
+
previousId: drizzle_orm_pg_core.PgColumn<{
|
|
1582
|
+
name: "previousId";
|
|
1583
|
+
tableName: "consent_log";
|
|
1584
|
+
dataType: "string";
|
|
1585
|
+
columnType: "PgText";
|
|
1586
|
+
data: string;
|
|
1587
|
+
driverParam: string;
|
|
1588
|
+
notNull: false;
|
|
1589
|
+
hasDefault: false;
|
|
1590
|
+
isPrimaryKey: false;
|
|
1591
|
+
isAutoincrement: false;
|
|
1592
|
+
hasRuntimeDefault: false;
|
|
1593
|
+
enumValues: [string, ...string[]];
|
|
1594
|
+
baseColumn: never;
|
|
1595
|
+
identity: undefined;
|
|
1596
|
+
generated: undefined;
|
|
1597
|
+
}, {}, {}>;
|
|
1598
|
+
createdAt: drizzle_orm_pg_core.PgColumn<{
|
|
1599
|
+
name: "createdAt";
|
|
1600
|
+
tableName: "consent_log";
|
|
1601
|
+
dataType: "date";
|
|
1602
|
+
columnType: "PgTimestamp";
|
|
1603
|
+
data: Date;
|
|
1604
|
+
driverParam: string;
|
|
1605
|
+
notNull: true;
|
|
1606
|
+
hasDefault: true;
|
|
1607
|
+
isPrimaryKey: false;
|
|
1608
|
+
isAutoincrement: false;
|
|
1609
|
+
hasRuntimeDefault: false;
|
|
1610
|
+
enumValues: undefined;
|
|
1611
|
+
baseColumn: never;
|
|
1612
|
+
identity: undefined;
|
|
1613
|
+
generated: undefined;
|
|
1614
|
+
}, {}, {}>;
|
|
1615
|
+
};
|
|
1616
|
+
dialect: "pg";
|
|
1617
|
+
}>;
|
|
1490
1618
|
declare const authThrottle: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
1491
1619
|
name: "auth_throttle";
|
|
1492
1620
|
schema: undefined;
|
|
@@ -1813,6 +1941,23 @@ declare const systemSettings: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
1813
1941
|
identity: undefined;
|
|
1814
1942
|
generated: undefined;
|
|
1815
1943
|
}, {}, {}>;
|
|
1944
|
+
consentRequired: drizzle_orm_pg_core.PgColumn<{
|
|
1945
|
+
name: "consentRequired";
|
|
1946
|
+
tableName: "system_settings";
|
|
1947
|
+
dataType: "boolean";
|
|
1948
|
+
columnType: "PgBoolean";
|
|
1949
|
+
data: boolean;
|
|
1950
|
+
driverParam: boolean;
|
|
1951
|
+
notNull: false;
|
|
1952
|
+
hasDefault: false;
|
|
1953
|
+
isPrimaryKey: false;
|
|
1954
|
+
isAutoincrement: false;
|
|
1955
|
+
hasRuntimeDefault: false;
|
|
1956
|
+
enumValues: undefined;
|
|
1957
|
+
baseColumn: never;
|
|
1958
|
+
identity: undefined;
|
|
1959
|
+
generated: undefined;
|
|
1960
|
+
}, {}, {}>;
|
|
1816
1961
|
updatedAt: drizzle_orm_pg_core.PgColumn<{
|
|
1817
1962
|
name: "updatedAt";
|
|
1818
1963
|
tableName: "system_settings";
|
|
@@ -1931,6 +2076,7 @@ declare const schema_RoleEnum: typeof RoleEnum;
|
|
|
1931
2076
|
declare const schema_accounts: typeof accounts;
|
|
1932
2077
|
declare const schema_activityLogs: typeof activityLogs;
|
|
1933
2078
|
declare const schema_authThrottle: typeof authThrottle;
|
|
2079
|
+
declare const schema_consentLog: typeof consentLog;
|
|
1934
2080
|
declare const schema_deviceFingerprints: typeof deviceFingerprints;
|
|
1935
2081
|
declare const schema_errorRefs: typeof errorRefs;
|
|
1936
2082
|
declare const schema_passkeys: typeof passkeys;
|
|
@@ -1940,7 +2086,7 @@ declare const schema_twoFactors: typeof twoFactors;
|
|
|
1940
2086
|
declare const schema_users: typeof users;
|
|
1941
2087
|
declare const schema_verifications: typeof verifications;
|
|
1942
2088
|
declare namespace schema {
|
|
1943
|
-
export { schema_ActivityActionEnum as ActivityActionEnum, schema_RoleEnum as RoleEnum, schema_accounts as accounts, schema_activityLogs as activityLogs, schema_authThrottle as authThrottle, schema_deviceFingerprints as deviceFingerprints, schema_errorRefs as errorRefs, schema_passkeys as passkeys, schema_sessions as sessions, schema_systemSettings as systemSettings, schema_twoFactors as twoFactors, schema_users as users, schema_verifications as verifications };
|
|
2089
|
+
export { schema_ActivityActionEnum as ActivityActionEnum, schema_RoleEnum as RoleEnum, schema_accounts as accounts, schema_activityLogs as activityLogs, schema_authThrottle as authThrottle, schema_consentLog as consentLog, schema_deviceFingerprints as deviceFingerprints, schema_errorRefs as errorRefs, schema_passkeys as passkeys, schema_sessions as sessions, schema_systemSettings as systemSettings, schema_twoFactors as twoFactors, schema_users as users, schema_verifications as verifications };
|
|
1944
2090
|
}
|
|
1945
2091
|
|
|
1946
|
-
export { ActivityActionEnum as A, RoleEnum as R, schema as a, accounts as b, activityLogs as c, authThrottle as d,
|
|
2092
|
+
export { ActivityActionEnum as A, RoleEnum as R, schema as a, accounts as b, activityLogs as c, authThrottle as d, consentLog as e, deviceFingerprints as f, errorRefs as g, sessions as h, passkeys as p, systemSettings as s, twoFactors as t, users as u, verifications as v };
|
package/dist/sessions/queries.js
CHANGED
|
@@ -24,6 +24,7 @@ __export(schema_exports, {
|
|
|
24
24
|
accounts: () => accounts,
|
|
25
25
|
activityLogs: () => activityLogs,
|
|
26
26
|
authThrottle: () => authThrottle,
|
|
27
|
+
consentLog: () => consentLog,
|
|
27
28
|
deviceFingerprints: () => deviceFingerprints,
|
|
28
29
|
errorRefs: () => errorRefs,
|
|
29
30
|
passkeys: () => passkeys,
|
|
@@ -178,10 +179,32 @@ var deviceFingerprints = pgCore.pgTable("device_fingerprint", {
|
|
|
178
179
|
userAgent: pgCore.text("userAgent"),
|
|
179
180
|
country: pgCore.text("country"),
|
|
180
181
|
city: pgCore.text("city"),
|
|
182
|
+
// Latest FingerprintJS signals for this device (lib/device-fingerprint.ts
|
|
183
|
+
// getDeviceSignals(): accessibility signals dropped, large values hashed),
|
|
184
|
+
// shown on the admin user page. Null for rows from before this column.
|
|
185
|
+
components: pgCore.jsonb("components").$type(),
|
|
181
186
|
createdAt: pgCore.timestamp("createdAt").notNull().defaultNow()
|
|
182
187
|
}, (table) => [
|
|
183
188
|
pgCore.unique("device_fingerprint_user_visitor").on(table.userId, table.visitorId)
|
|
184
189
|
]);
|
|
190
|
+
var consentLog = pgCore.pgTable("consent_log", {
|
|
191
|
+
id: pgCore.text("id").notNull().primaryKey().$defaultFn(() => cuid2.createId()),
|
|
192
|
+
userId: pgCore.text("userId").notNull().references(() => users.id, { onDelete: "cascade" }),
|
|
193
|
+
// The cookie_consent value: "all", "necessary" or a comma list of purposes.
|
|
194
|
+
choice: pgCore.text("choice").notNull(),
|
|
195
|
+
// CONSENT_VERSION (lib/cookie-names.ts) at the time — which banner/policy
|
|
196
|
+
// wording the user agreed to.
|
|
197
|
+
version: pgCore.integer("version").notNull(),
|
|
198
|
+
// id of the user's record this one follows ("" for their first). Unique per
|
|
199
|
+
// user, so concurrent posts from several tabs that all saw the same latest
|
|
200
|
+
// record can't each insert a duplicate — one wins, the rest conflict. Works
|
|
201
|
+
// without transactions (neon-http has none). Null on rows from before it.
|
|
202
|
+
previousId: pgCore.text("previousId"),
|
|
203
|
+
createdAt: pgCore.timestamp("createdAt").notNull().defaultNow()
|
|
204
|
+
}, (table) => [
|
|
205
|
+
pgCore.index("consent_log_user_idx").on(table.userId, table.createdAt),
|
|
206
|
+
pgCore.unique("consent_log_chain").on(table.userId, table.previousId)
|
|
207
|
+
]);
|
|
185
208
|
var authThrottle = pgCore.pgTable("auth_throttle", {
|
|
186
209
|
fingerprint: pgCore.text("fingerprint").notNull().primaryKey(),
|
|
187
210
|
count: pgCore.integer("count").notNull().default(0),
|
|
@@ -211,6 +234,13 @@ var systemSettings = pgCore.pgTable("system_settings", {
|
|
|
211
234
|
// Attach the error a user hit to feedback they send from it (see
|
|
212
235
|
// lib/feedback-route.ts). Off = only what the user typed is sent.
|
|
213
236
|
feedbackAttachErrors: pgCore.boolean("feedbackAttachErrors").notNull().default(true),
|
|
237
|
+
// GDPR/ePrivacy consent mode. On: cookie banner, FingerprintJS and One Tap
|
|
238
|
+
// only after "Accept all", device record erased on withdrawal. Off (no EU/UK
|
|
239
|
+
// users): no banner, treated as consented. Null = follow
|
|
240
|
+
// NEXT_PUBLIC_COOKIE_BANNER (nullable so migrating never flips a deployed
|
|
241
|
+
// banner on or off). proxy.ts mirrors the effective value into the
|
|
242
|
+
// consent_required cookie for the client (lib/cookie-consent.ts).
|
|
243
|
+
consentRequired: pgCore.boolean("consentRequired"),
|
|
214
244
|
updatedAt: pgCore.timestamp("updatedAt").notNull().defaultNow(),
|
|
215
245
|
// Who last changed a setting. This row doesn't "belong" to that admin the
|
|
216
246
|
// way sessions/activityLogs belong to their user, so deleting that admin's
|
|
@@ -232,6 +262,12 @@ var envSchema = zod.z.object({
|
|
|
232
262
|
PORT: zod.z.string().default("3000").transform(Number),
|
|
233
263
|
DATABASE_URL: zod.z.string().default(""),
|
|
234
264
|
RESEND_API_KEY: zod.z.string().default(""),
|
|
265
|
+
// Full access key for marketing broadcasts (admin Marketing email page).
|
|
266
|
+
// Blank = use RESEND_API_KEY.
|
|
267
|
+
RESEND_BROADCAST_API_KEY: zod.z.string().default(""),
|
|
268
|
+
// Resend segment users join from the dashboard "Email updates" toggle.
|
|
269
|
+
// Blank = toggle hidden.
|
|
270
|
+
RESEND_MARKETING_SEGMENT_ID: zod.z.string().default(""),
|
|
235
271
|
// Sender for every transactional email. Must be on a domain verified in
|
|
236
272
|
// your Resend account.
|
|
237
273
|
EMAIL_FROM: zod.z.string().default("Acme <onboarding@xavierkhew.xyz>"),
|