@xk2800/nextjs-template 0.7.1-beta.3 → 0.7.1-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +1 -1
  2. package/components/auth/deviceCheck.tsx +47 -6
  3. package/components/auth/oneTap.tsx +5 -5
  4. package/components/dashboard/admin/adminUserConsentCard.tsx +79 -0
  5. package/components/dashboard/admin/adminUserDevicesCard.tsx +80 -0
  6. package/components/dashboard/admin/systemSettingsForm.tsx +33 -0
  7. package/components/dashboard/admin/systemSettingsSection.tsx +8 -2
  8. package/components/site/cookie-banner.tsx +109 -7
  9. package/dist/activity/logger.js +30 -0
  10. package/dist/activity/logger.js.map +1 -1
  11. package/dist/activity/logger.mjs +3 -3
  12. package/dist/activity/queries.d.mts +1 -1
  13. package/dist/activity/queries.d.ts +1 -1
  14. package/dist/activity/queries.js +30 -0
  15. package/dist/activity/queries.js.map +1 -1
  16. package/dist/activity/queries.mjs +2 -2
  17. package/dist/admin/queries.d.mts +19 -1
  18. package/dist/admin/queries.d.ts +19 -1
  19. package/dist/admin/queries.js +58 -0
  20. package/dist/admin/queries.js.map +1 -1
  21. package/dist/admin/queries.mjs +25 -4
  22. package/dist/admin/queries.mjs.map +1 -1
  23. package/dist/api/feedback.js +46 -2
  24. package/dist/api/feedback.js.map +1 -1
  25. package/dist/api/feedback.mjs +7 -7
  26. package/dist/auth/helpers.js +44 -0
  27. package/dist/auth/helpers.js.map +1 -1
  28. package/dist/auth/helpers.mjs +6 -6
  29. package/dist/auth/index.js +44 -0
  30. package/dist/auth/index.js.map +1 -1
  31. package/dist/auth/index.mjs +6 -6
  32. package/dist/{chunk-XWVAJXAG.mjs → chunk-4GGLYS5R.mjs} +20 -8
  33. package/dist/chunk-4GGLYS5R.mjs.map +1 -0
  34. package/dist/{chunk-KAEA35OC.mjs → chunk-6KTSULA5.mjs} +4 -4
  35. package/dist/{chunk-KAEA35OC.mjs.map → chunk-6KTSULA5.mjs.map} +1 -1
  36. package/dist/{chunk-N6ECRCHY.mjs → chunk-6OAHCEDJ.mjs} +4 -3
  37. package/dist/chunk-6OAHCEDJ.mjs.map +1 -0
  38. package/dist/{chunk-3MGEAGHU.mjs → chunk-F776DQAM.mjs} +10 -5
  39. package/dist/chunk-F776DQAM.mjs.map +1 -0
  40. package/dist/{chunk-WZDAMCUX.mjs → chunk-F7CG5CA3.mjs} +3 -3
  41. package/dist/{chunk-WZDAMCUX.mjs.map → chunk-F7CG5CA3.mjs.map} +1 -1
  42. package/dist/{chunk-VQ5B4MA7.mjs → chunk-FVLMSLTX.mjs} +4 -4
  43. package/dist/{chunk-VQ5B4MA7.mjs.map → chunk-FVLMSLTX.mjs.map} +1 -1
  44. package/dist/{chunk-ZQCALTKB.mjs → chunk-TR5XFBTD.mjs} +34 -4
  45. package/dist/chunk-TR5XFBTD.mjs.map +1 -0
  46. package/dist/db/index.d.mts +1 -1
  47. package/dist/db/index.d.ts +1 -1
  48. package/dist/db/index.js +30 -0
  49. package/dist/db/index.js.map +1 -1
  50. package/dist/db/index.mjs +2 -2
  51. package/dist/db/schema.d.mts +1 -1
  52. package/dist/db/schema.d.ts +1 -1
  53. package/dist/db/schema.js +30 -0
  54. package/dist/db/schema.js.map +1 -1
  55. package/dist/db/schema.mjs +1 -1
  56. package/dist/errors.js +30 -0
  57. package/dist/errors.js.map +1 -1
  58. package/dist/errors.mjs +3 -3
  59. package/dist/{schema-UuqxoOzS.d.mts → schema-CN_Y6EXv.d.mts} +148 -2
  60. package/dist/{schema-UuqxoOzS.d.ts → schema-CN_Y6EXv.d.ts} +148 -2
  61. package/dist/sessions/queries.js +30 -0
  62. package/dist/sessions/queries.js.map +1 -1
  63. package/dist/sessions/queries.mjs +2 -2
  64. package/dist/settings/queries.d.mts +4 -3
  65. package/dist/settings/queries.d.ts +4 -3
  66. package/dist/settings/queries.js +36 -0
  67. package/dist/settings/queries.js.map +1 -1
  68. package/dist/settings/queries.mjs +3 -3
  69. package/dist/users/queries.js +30 -0
  70. package/dist/users/queries.js.map +1 -1
  71. package/dist/users/queries.mjs +2 -2
  72. package/lib/cookie-consent.ts +72 -20
  73. package/lib/cookie-names.ts +47 -0
  74. package/lib/device-fingerprint.ts +66 -10
  75. package/package.json +7 -2
  76. package/dist/chunk-3MGEAGHU.mjs.map +0 -1
  77. package/dist/chunk-N6ECRCHY.mjs.map +0 -1
  78. package/dist/chunk-XWVAJXAG.mjs.map +0 -1
  79. package/dist/chunk-ZQCALTKB.mjs.map +0 -1
@@ -1,10 +1,10 @@
1
- import { lookupErrorDetail, unexpectedErrorMessage } from '../chunk-KAEA35OC.mjs';
2
- import { auth, getResend, EMAIL_FROM } from '../chunk-XWVAJXAG.mjs';
3
- import '../chunk-VQ5B4MA7.mjs';
4
- import '../chunk-N6ECRCHY.mjs';
5
- import { getSystemSettings } from '../chunk-3MGEAGHU.mjs';
6
- import '../chunk-WZDAMCUX.mjs';
7
- import '../chunk-ZQCALTKB.mjs';
1
+ import { lookupErrorDetail, unexpectedErrorMessage } from '../chunk-6KTSULA5.mjs';
2
+ import { auth, getResend, EMAIL_FROM } from '../chunk-4GGLYS5R.mjs';
3
+ import '../chunk-FVLMSLTX.mjs';
4
+ import '../chunk-6OAHCEDJ.mjs';
5
+ import { getSystemSettings } from '../chunk-F776DQAM.mjs';
6
+ import '../chunk-F7CG5CA3.mjs';
7
+ import '../chunk-TR5XFBTD.mjs';
8
8
  import { config } from '../chunk-TMJYAOC2.mjs';
9
9
  import '../chunk-3465SI5N.mjs';
10
10
  import 'server-only';
@@ -210,6 +210,7 @@ __export(schema_exports, {
210
210
  accounts: () => accounts,
211
211
  activityLogs: () => activityLogs,
212
212
  authThrottle: () => authThrottle,
213
+ consentLog: () => consentLog,
213
214
  deviceFingerprints: () => deviceFingerprints,
214
215
  errorRefs: () => errorRefs,
215
216
  passkeys: () => passkeys,
@@ -364,10 +365,32 @@ var deviceFingerprints = pgCore.pgTable("device_fingerprint", {
364
365
  userAgent: pgCore.text("userAgent"),
365
366
  country: pgCore.text("country"),
366
367
  city: pgCore.text("city"),
368
+ // Latest FingerprintJS signals for this device (lib/device-fingerprint.ts
369
+ // getDeviceSignals(): accessibility signals dropped, large values hashed),
370
+ // shown on the admin user page. Null for rows from before this column.
371
+ components: pgCore.jsonb("components").$type(),
367
372
  createdAt: pgCore.timestamp("createdAt").notNull().defaultNow()
368
373
  }, (table) => [
369
374
  pgCore.unique("device_fingerprint_user_visitor").on(table.userId, table.visitorId)
370
375
  ]);
376
+ var consentLog = pgCore.pgTable("consent_log", {
377
+ id: pgCore.text("id").notNull().primaryKey().$defaultFn(() => cuid2.createId()),
378
+ userId: pgCore.text("userId").notNull().references(() => users.id, { onDelete: "cascade" }),
379
+ // The cookie_consent value: "all", "necessary" or a comma list of purposes.
380
+ choice: pgCore.text("choice").notNull(),
381
+ // CONSENT_VERSION (lib/cookie-names.ts) at the time — which banner/policy
382
+ // wording the user agreed to.
383
+ version: pgCore.integer("version").notNull(),
384
+ // id of the user's record this one follows ("" for their first). Unique per
385
+ // user, so concurrent posts from several tabs that all saw the same latest
386
+ // record can't each insert a duplicate — one wins, the rest conflict. Works
387
+ // without transactions (neon-http has none). Null on rows from before it.
388
+ previousId: pgCore.text("previousId"),
389
+ createdAt: pgCore.timestamp("createdAt").notNull().defaultNow()
390
+ }, (table) => [
391
+ pgCore.index("consent_log_user_idx").on(table.userId, table.createdAt),
392
+ pgCore.unique("consent_log_chain").on(table.userId, table.previousId)
393
+ ]);
371
394
  var authThrottle = pgCore.pgTable("auth_throttle", {
372
395
  fingerprint: pgCore.text("fingerprint").notNull().primaryKey(),
373
396
  count: pgCore.integer("count").notNull().default(0),
@@ -397,6 +420,13 @@ var systemSettings = pgCore.pgTable("system_settings", {
397
420
  // Attach the error a user hit to feedback they send from it (see
398
421
  // lib/feedback-route.ts). Off = only what the user typed is sent.
399
422
  feedbackAttachErrors: pgCore.boolean("feedbackAttachErrors").notNull().default(true),
423
+ // GDPR/ePrivacy consent mode. On: cookie banner, FingerprintJS and One Tap
424
+ // only after "Accept all", device record erased on withdrawal. Off (no EU/UK
425
+ // users): no banner, treated as consented. Null = follow
426
+ // NEXT_PUBLIC_COOKIE_BANNER (nullable so migrating never flips a deployed
427
+ // banner on or off). proxy.ts mirrors the effective value into the
428
+ // consent_required cookie for the client (lib/cookie-consent.ts).
429
+ consentRequired: pgCore.boolean("consentRequired"),
400
430
  updatedAt: pgCore.timestamp("updatedAt").notNull().defaultNow(),
401
431
  // Who last changed a setting. This row doesn't "belong" to that admin the
402
432
  // way sessions/activityLogs belong to their user, so deleting that admin's
@@ -557,6 +587,7 @@ var DEVICE_FINGERPRINT_HEADER = "x-device-fingerprint";
557
587
  var WINDOW_MS = 15 * 60 * 1e3;
558
588
  var MAX = 10;
559
589
  var MAX_IP = MAX * 3;
590
+ var RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
560
591
  function isOverLimit(row, now, max = MAX) {
561
592
  if (!row) return false;
562
593
  if (now - row.windowStart.getTime() >= WINDOW_MS) return false;
@@ -594,6 +625,18 @@ async function recordDeviceAttempt(fingerprint, meta) {
594
625
  } catch (error) {
595
626
  console.error("auth-throttle write failed", error);
596
627
  }
628
+ await pruneStaleRows(now);
629
+ }
630
+ var PRUNE_EVERY_MS = 60 * 60 * 1e3;
631
+ var lastPrune = 0;
632
+ async function pruneStaleRows(now = /* @__PURE__ */ new Date()) {
633
+ if (now.getTime() - lastPrune < PRUNE_EVERY_MS) return;
634
+ lastPrune = now.getTime();
635
+ try {
636
+ await db.delete(authThrottle).where(drizzleOrm.lt(authThrottle.lastAttemptAt, new Date(now.getTime() - RETENTION_MS)));
637
+ } catch (error) {
638
+ console.error("auth-throttle prune failed", error);
639
+ }
597
640
  }
598
641
  async function clearDeviceThrottle(fingerprint) {
599
642
  try {
@@ -616,6 +659,7 @@ function fallbackSettings() {
616
659
  authEnableOneTap: config.AUTH_ENABLE_ONE_TAP,
617
660
  enableSessionRevocation: config.ENABLE_SESSION_REVOCATION,
618
661
  feedbackAttachErrors: true,
662
+ consentRequired: null,
619
663
  updatedAt: /* @__PURE__ */ new Date(0),
620
664
  updatedBy: null
621
665
  };