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

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 (83) 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.d.mts +3 -3
  27. package/dist/auth/helpers.d.ts +3 -3
  28. package/dist/auth/helpers.js +44 -0
  29. package/dist/auth/helpers.js.map +1 -1
  30. package/dist/auth/helpers.mjs +6 -6
  31. package/dist/auth/index.js +44 -0
  32. package/dist/auth/index.js.map +1 -1
  33. package/dist/auth/index.mjs +6 -6
  34. package/dist/auth-client/index.d.mts +16 -16
  35. package/dist/auth-client/index.d.ts +16 -16
  36. package/dist/{chunk-XWVAJXAG.mjs → chunk-4GGLYS5R.mjs} +20 -8
  37. package/dist/chunk-4GGLYS5R.mjs.map +1 -0
  38. package/dist/{chunk-KAEA35OC.mjs → chunk-6KTSULA5.mjs} +4 -4
  39. package/dist/{chunk-KAEA35OC.mjs.map → chunk-6KTSULA5.mjs.map} +1 -1
  40. package/dist/{chunk-N6ECRCHY.mjs → chunk-6OAHCEDJ.mjs} +4 -3
  41. package/dist/chunk-6OAHCEDJ.mjs.map +1 -0
  42. package/dist/{chunk-3MGEAGHU.mjs → chunk-F776DQAM.mjs} +10 -5
  43. package/dist/chunk-F776DQAM.mjs.map +1 -0
  44. package/dist/{chunk-WZDAMCUX.mjs → chunk-F7CG5CA3.mjs} +3 -3
  45. package/dist/{chunk-WZDAMCUX.mjs.map → chunk-F7CG5CA3.mjs.map} +1 -1
  46. package/dist/{chunk-VQ5B4MA7.mjs → chunk-FVLMSLTX.mjs} +4 -4
  47. package/dist/{chunk-VQ5B4MA7.mjs.map → chunk-FVLMSLTX.mjs.map} +1 -1
  48. package/dist/{chunk-ZQCALTKB.mjs → chunk-TR5XFBTD.mjs} +34 -4
  49. package/dist/chunk-TR5XFBTD.mjs.map +1 -0
  50. package/dist/db/index.d.mts +1 -1
  51. package/dist/db/index.d.ts +1 -1
  52. package/dist/db/index.js +30 -0
  53. package/dist/db/index.js.map +1 -1
  54. package/dist/db/index.mjs +2 -2
  55. package/dist/db/schema.d.mts +1 -1
  56. package/dist/db/schema.d.ts +1 -1
  57. package/dist/db/schema.js +30 -0
  58. package/dist/db/schema.js.map +1 -1
  59. package/dist/db/schema.mjs +1 -1
  60. package/dist/errors.js +30 -0
  61. package/dist/errors.js.map +1 -1
  62. package/dist/errors.mjs +3 -3
  63. package/dist/{schema-UuqxoOzS.d.mts → schema-CN_Y6EXv.d.mts} +148 -2
  64. package/dist/{schema-UuqxoOzS.d.ts → schema-CN_Y6EXv.d.ts} +148 -2
  65. package/dist/sessions/queries.js +30 -0
  66. package/dist/sessions/queries.js.map +1 -1
  67. package/dist/sessions/queries.mjs +2 -2
  68. package/dist/settings/queries.d.mts +4 -3
  69. package/dist/settings/queries.d.ts +4 -3
  70. package/dist/settings/queries.js +36 -0
  71. package/dist/settings/queries.js.map +1 -1
  72. package/dist/settings/queries.mjs +3 -3
  73. package/dist/users/queries.js +30 -0
  74. package/dist/users/queries.js.map +1 -1
  75. package/dist/users/queries.mjs +2 -2
  76. package/lib/cookie-consent.ts +72 -20
  77. package/lib/cookie-names.ts +47 -0
  78. package/lib/device-fingerprint.ts +66 -10
  79. package/package.json +7 -2
  80. package/dist/chunk-3MGEAGHU.mjs.map +0 -1
  81. package/dist/chunk-N6ECRCHY.mjs.map +0 -1
  82. package/dist/chunk-XWVAJXAG.mjs.map +0 -1
  83. package/dist/chunk-ZQCALTKB.mjs.map +0 -1
@@ -207,6 +207,7 @@ __export(schema_exports, {
207
207
  accounts: () => accounts,
208
208
  activityLogs: () => activityLogs,
209
209
  authThrottle: () => authThrottle,
210
+ consentLog: () => consentLog,
210
211
  deviceFingerprints: () => deviceFingerprints,
211
212
  errorRefs: () => errorRefs,
212
213
  passkeys: () => passkeys,
@@ -361,10 +362,32 @@ var deviceFingerprints = pgCore.pgTable("device_fingerprint", {
361
362
  userAgent: pgCore.text("userAgent"),
362
363
  country: pgCore.text("country"),
363
364
  city: pgCore.text("city"),
365
+ // Latest FingerprintJS signals for this device (lib/device-fingerprint.ts
366
+ // getDeviceSignals(): accessibility signals dropped, large values hashed),
367
+ // shown on the admin user page. Null for rows from before this column.
368
+ components: pgCore.jsonb("components").$type(),
364
369
  createdAt: pgCore.timestamp("createdAt").notNull().defaultNow()
365
370
  }, (table) => [
366
371
  pgCore.unique("device_fingerprint_user_visitor").on(table.userId, table.visitorId)
367
372
  ]);
373
+ var consentLog = pgCore.pgTable("consent_log", {
374
+ id: pgCore.text("id").notNull().primaryKey().$defaultFn(() => cuid2.createId()),
375
+ userId: pgCore.text("userId").notNull().references(() => users.id, { onDelete: "cascade" }),
376
+ // The cookie_consent value: "all", "necessary" or a comma list of purposes.
377
+ choice: pgCore.text("choice").notNull(),
378
+ // CONSENT_VERSION (lib/cookie-names.ts) at the time — which banner/policy
379
+ // wording the user agreed to.
380
+ version: pgCore.integer("version").notNull(),
381
+ // id of the user's record this one follows ("" for their first). Unique per
382
+ // user, so concurrent posts from several tabs that all saw the same latest
383
+ // record can't each insert a duplicate — one wins, the rest conflict. Works
384
+ // without transactions (neon-http has none). Null on rows from before it.
385
+ previousId: pgCore.text("previousId"),
386
+ createdAt: pgCore.timestamp("createdAt").notNull().defaultNow()
387
+ }, (table) => [
388
+ pgCore.index("consent_log_user_idx").on(table.userId, table.createdAt),
389
+ pgCore.unique("consent_log_chain").on(table.userId, table.previousId)
390
+ ]);
368
391
  var authThrottle = pgCore.pgTable("auth_throttle", {
369
392
  fingerprint: pgCore.text("fingerprint").notNull().primaryKey(),
370
393
  count: pgCore.integer("count").notNull().default(0),
@@ -394,6 +417,13 @@ var systemSettings = pgCore.pgTable("system_settings", {
394
417
  // Attach the error a user hit to feedback they send from it (see
395
418
  // lib/feedback-route.ts). Off = only what the user typed is sent.
396
419
  feedbackAttachErrors: pgCore.boolean("feedbackAttachErrors").notNull().default(true),
420
+ // GDPR/ePrivacy consent mode. On: cookie banner, FingerprintJS and One Tap
421
+ // only after "Accept all", device record erased on withdrawal. Off (no EU/UK
422
+ // users): no banner, treated as consented. Null = follow
423
+ // NEXT_PUBLIC_COOKIE_BANNER (nullable so migrating never flips a deployed
424
+ // banner on or off). proxy.ts mirrors the effective value into the
425
+ // consent_required cookie for the client (lib/cookie-consent.ts).
426
+ consentRequired: pgCore.boolean("consentRequired"),
397
427
  updatedAt: pgCore.timestamp("updatedAt").notNull().defaultNow(),
398
428
  // Who last changed a setting. This row doesn't "belong" to that admin the
399
429
  // way sessions/activityLogs belong to their user, so deleting that admin's
@@ -554,6 +584,7 @@ var DEVICE_FINGERPRINT_HEADER = "x-device-fingerprint";
554
584
  var WINDOW_MS = 15 * 60 * 1e3;
555
585
  var MAX = 10;
556
586
  var MAX_IP = MAX * 3;
587
+ var RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
557
588
  function isOverLimit(row, now, max = MAX) {
558
589
  if (!row) return false;
559
590
  if (now - row.windowStart.getTime() >= WINDOW_MS) return false;
@@ -591,6 +622,18 @@ async function recordDeviceAttempt(fingerprint, meta) {
591
622
  } catch (error) {
592
623
  console.error("auth-throttle write failed", error);
593
624
  }
625
+ await pruneStaleRows(now);
626
+ }
627
+ var PRUNE_EVERY_MS = 60 * 60 * 1e3;
628
+ var lastPrune = 0;
629
+ async function pruneStaleRows(now = /* @__PURE__ */ new Date()) {
630
+ if (now.getTime() - lastPrune < PRUNE_EVERY_MS) return;
631
+ lastPrune = now.getTime();
632
+ try {
633
+ await db.delete(authThrottle).where(drizzleOrm.lt(authThrottle.lastAttemptAt, new Date(now.getTime() - RETENTION_MS)));
634
+ } catch (error) {
635
+ console.error("auth-throttle prune failed", error);
636
+ }
594
637
  }
595
638
  async function clearDeviceThrottle(fingerprint) {
596
639
  try {
@@ -613,6 +656,7 @@ function fallbackSettings() {
613
656
  authEnableOneTap: config.AUTH_ENABLE_ONE_TAP,
614
657
  enableSessionRevocation: config.ENABLE_SESSION_REVOCATION,
615
658
  feedbackAttachErrors: true,
659
+ consentRequired: null,
616
660
  updatedAt: /* @__PURE__ */ new Date(0),
617
661
  updatedBy: null
618
662
  };