@xk2800/nextjs-template 0.6.1-beta.3 → 0.7.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.
Files changed (105) hide show
  1. package/README.md +56 -321
  2. package/components/dashboard/admin/adminUsersTable.tsx +36 -2
  3. package/components/dashboard/admin/feedbackTestForm.tsx +55 -0
  4. package/components/dashboard/admin/systemSettingsForm.tsx +28 -0
  5. package/components/dashboard/appSidebar.tsx +4 -4
  6. package/components/dashboard/deleteAccountCard.tsx +137 -0
  7. package/components/dashboard/errorFeedback.tsx +65 -0
  8. package/components/dashboard/feedbackDialog.tsx +160 -0
  9. package/components/dashboard/installAppCard.tsx +187 -0
  10. package/components/site/cookie-banner.tsx +57 -0
  11. package/components/ui/button.tsx +1 -1
  12. package/components/ui/file-upload.tsx +178 -0
  13. package/components/ui/input.tsx +1 -1
  14. package/components/ui/separator.tsx +1 -1
  15. package/components/ui/sheet.tsx +1 -1
  16. package/components/ui/sidebar.tsx +8 -8
  17. package/components/ui/skeleton.tsx +1 -1
  18. package/components/ui/tooltip.tsx +1 -1
  19. package/dist/activity/logger.js +21 -1
  20. package/dist/activity/logger.js.map +1 -1
  21. package/dist/activity/logger.mjs +4 -4
  22. package/dist/activity/queries.d.mts +1 -1
  23. package/dist/activity/queries.d.ts +1 -1
  24. package/dist/activity/queries.js +21 -1
  25. package/dist/activity/queries.js.map +1 -1
  26. package/dist/activity/queries.mjs +3 -3
  27. package/dist/admin/queries.js +21 -1
  28. package/dist/admin/queries.js.map +1 -1
  29. package/dist/admin/queries.mjs +3 -3
  30. package/dist/api/feedback.d.mts +23 -0
  31. package/dist/api/feedback.d.ts +23 -0
  32. package/dist/api/feedback.js +1224 -0
  33. package/dist/api/feedback.js.map +1 -0
  34. package/dist/api/feedback.mjs +136 -0
  35. package/dist/api/feedback.mjs.map +1 -0
  36. package/dist/auth/helpers.d.mts +3 -3
  37. package/dist/auth/helpers.d.ts +3 -3
  38. package/dist/auth/helpers.js +45 -4
  39. package/dist/auth/helpers.js.map +1 -1
  40. package/dist/auth/helpers.mjs +7 -7
  41. package/dist/auth/helpers.mjs.map +1 -1
  42. package/dist/auth/index.d.mts +8 -2
  43. package/dist/auth/index.d.ts +8 -2
  44. package/dist/auth/index.js +44 -3
  45. package/dist/auth/index.js.map +1 -1
  46. package/dist/auth/index.mjs +6 -6
  47. package/dist/auth-client/index.d.mts +16 -16
  48. package/dist/auth-client/index.d.ts +16 -16
  49. package/dist/{chunk-IF3JZRSZ.mjs → chunk-3MGEAGHU.mjs} +6 -5
  50. package/dist/chunk-3MGEAGHU.mjs.map +1 -0
  51. package/dist/chunk-KAEA35OC.mjs +76 -0
  52. package/dist/chunk-KAEA35OC.mjs.map +1 -0
  53. package/dist/{chunk-GTPTVNY2.mjs → chunk-TMJYAOC2.mjs} +10 -2
  54. package/dist/chunk-TMJYAOC2.mjs.map +1 -0
  55. package/dist/{chunk-OHAUKE2Q.mjs → chunk-VQ5B4MA7.mjs} +4 -4
  56. package/dist/{chunk-OHAUKE2Q.mjs.map → chunk-VQ5B4MA7.mjs.map} +1 -1
  57. package/dist/{chunk-5PYDAD4P.mjs → chunk-WZDAMCUX.mjs} +4 -4
  58. package/dist/{chunk-5PYDAD4P.mjs.map → chunk-WZDAMCUX.mjs.map} +1 -1
  59. package/dist/{chunk-V72CFFU2.mjs → chunk-XWVAJXAG.mjs} +31 -11
  60. package/dist/chunk-XWVAJXAG.mjs.map +1 -0
  61. package/dist/{chunk-4B7MJOLH.mjs → chunk-ZQCALTKB.mjs} +17 -5
  62. package/dist/chunk-ZQCALTKB.mjs.map +1 -0
  63. package/dist/config/env.d.mts +3 -0
  64. package/dist/config/env.d.ts +3 -0
  65. package/dist/config/env.js +8 -0
  66. package/dist/config/env.js.map +1 -1
  67. package/dist/config/env.mjs +1 -1
  68. package/dist/db/index.d.mts +1 -1
  69. package/dist/db/index.d.ts +1 -1
  70. package/dist/db/index.js +21 -1
  71. package/dist/db/index.js.map +1 -1
  72. package/dist/db/index.mjs +3 -3
  73. package/dist/db/schema.d.mts +1 -1
  74. package/dist/db/schema.d.ts +1 -1
  75. package/dist/db/schema.js +13 -1
  76. package/dist/db/schema.js.map +1 -1
  77. package/dist/db/schema.mjs +1 -1
  78. package/dist/errors.d.mts +29 -0
  79. package/dist/errors.d.ts +29 -0
  80. package/dist/errors.js +365 -0
  81. package/dist/errors.js.map +1 -0
  82. package/dist/errors.mjs +7 -0
  83. package/dist/errors.mjs.map +1 -0
  84. package/dist/{schema-BghJ8N4X.d.mts → schema-BNSBWNjK.d.mts} +99 -6
  85. package/dist/{schema-BghJ8N4X.d.ts → schema-BNSBWNjK.d.ts} +99 -6
  86. package/dist/sessions/queries.js +21 -1
  87. package/dist/sessions/queries.js.map +1 -1
  88. package/dist/sessions/queries.mjs +3 -3
  89. package/dist/settings/queries.d.mts +2 -2
  90. package/dist/settings/queries.d.ts +2 -2
  91. package/dist/settings/queries.js +22 -1
  92. package/dist/settings/queries.js.map +1 -1
  93. package/dist/settings/queries.mjs +4 -4
  94. package/dist/users/queries.d.mts +3 -3
  95. package/dist/users/queries.d.ts +3 -3
  96. package/dist/users/queries.js +21 -1
  97. package/dist/users/queries.js.map +1 -1
  98. package/dist/users/queries.mjs +3 -3
  99. package/hooks/use-mobile.ts +19 -0
  100. package/lib/device-fingerprint.ts +2 -3
  101. package/package.json +35 -32
  102. package/dist/chunk-4B7MJOLH.mjs.map +0 -1
  103. package/dist/chunk-GTPTVNY2.mjs.map +0 -1
  104. package/dist/chunk-IF3JZRSZ.mjs.map +0 -1
  105. package/dist/chunk-V72CFFU2.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"errors.mjs"}
@@ -1,7 +1,7 @@
1
1
  import * as drizzle_orm from 'drizzle-orm';
2
2
  import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
3
3
 
4
- declare const RoleEnum: drizzle_orm_pg_core.PgEnum<["user", "admin"]>;
4
+ declare const RoleEnum: drizzle_orm_pg_core.PgEnum<["user", "admin", "tester"]>;
5
5
  declare const ActivityActionEnum: drizzle_orm_pg_core.PgEnum<["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"]>;
6
6
  declare const users: drizzle_orm_pg_core.PgTableWithColumns<{
7
7
  name: "user";
@@ -114,14 +114,14 @@ declare const users: drizzle_orm_pg_core.PgTableWithColumns<{
114
114
  tableName: "user";
115
115
  dataType: "string";
116
116
  columnType: "PgEnumColumn";
117
- data: "user" | "admin";
117
+ data: "user" | "admin" | "tester";
118
118
  driverParam: string;
119
119
  notNull: true;
120
120
  hasDefault: true;
121
121
  isPrimaryKey: false;
122
122
  isAutoincrement: false;
123
123
  hasRuntimeDefault: false;
124
- enumValues: ["user", "admin"];
124
+ enumValues: ["user", "admin", "tester"];
125
125
  baseColumn: never;
126
126
  identity: undefined;
127
127
  generated: undefined;
@@ -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: "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";
1145
+ data: "login_failed" | "login" | "logout" | "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;
@@ -1796,6 +1796,23 @@ declare const systemSettings: drizzle_orm_pg_core.PgTableWithColumns<{
1796
1796
  identity: undefined;
1797
1797
  generated: undefined;
1798
1798
  }, {}, {}>;
1799
+ feedbackAttachErrors: drizzle_orm_pg_core.PgColumn<{
1800
+ name: "feedbackAttachErrors";
1801
+ tableName: "system_settings";
1802
+ dataType: "boolean";
1803
+ columnType: "PgBoolean";
1804
+ data: boolean;
1805
+ driverParam: boolean;
1806
+ notNull: true;
1807
+ hasDefault: true;
1808
+ isPrimaryKey: false;
1809
+ isAutoincrement: false;
1810
+ hasRuntimeDefault: false;
1811
+ enumValues: undefined;
1812
+ baseColumn: never;
1813
+ identity: undefined;
1814
+ generated: undefined;
1815
+ }, {}, {}>;
1799
1816
  updatedAt: drizzle_orm_pg_core.PgColumn<{
1800
1817
  name: "updatedAt";
1801
1818
  tableName: "system_settings";
@@ -1833,6 +1850,81 @@ declare const systemSettings: drizzle_orm_pg_core.PgTableWithColumns<{
1833
1850
  };
1834
1851
  dialect: "pg";
1835
1852
  }>;
1853
+ declare const errorRefs: drizzle_orm_pg_core.PgTableWithColumns<{
1854
+ name: "error_refs";
1855
+ schema: undefined;
1856
+ columns: {
1857
+ ref: drizzle_orm_pg_core.PgColumn<{
1858
+ name: "ref";
1859
+ tableName: "error_refs";
1860
+ dataType: "string";
1861
+ columnType: "PgText";
1862
+ data: string;
1863
+ driverParam: string;
1864
+ notNull: true;
1865
+ hasDefault: false;
1866
+ isPrimaryKey: true;
1867
+ isAutoincrement: false;
1868
+ hasRuntimeDefault: false;
1869
+ enumValues: [string, ...string[]];
1870
+ baseColumn: never;
1871
+ identity: undefined;
1872
+ generated: undefined;
1873
+ }, {}, {}>;
1874
+ message: drizzle_orm_pg_core.PgColumn<{
1875
+ name: "message";
1876
+ tableName: "error_refs";
1877
+ dataType: "string";
1878
+ columnType: "PgText";
1879
+ data: string;
1880
+ driverParam: string;
1881
+ notNull: true;
1882
+ hasDefault: false;
1883
+ isPrimaryKey: false;
1884
+ isAutoincrement: false;
1885
+ hasRuntimeDefault: false;
1886
+ enumValues: [string, ...string[]];
1887
+ baseColumn: never;
1888
+ identity: undefined;
1889
+ generated: undefined;
1890
+ }, {}, {}>;
1891
+ detail: drizzle_orm_pg_core.PgColumn<{
1892
+ name: "detail";
1893
+ tableName: "error_refs";
1894
+ dataType: "string";
1895
+ columnType: "PgText";
1896
+ data: string;
1897
+ driverParam: string;
1898
+ notNull: true;
1899
+ hasDefault: false;
1900
+ isPrimaryKey: false;
1901
+ isAutoincrement: false;
1902
+ hasRuntimeDefault: false;
1903
+ enumValues: [string, ...string[]];
1904
+ baseColumn: never;
1905
+ identity: undefined;
1906
+ generated: undefined;
1907
+ }, {}, {}>;
1908
+ createdAt: drizzle_orm_pg_core.PgColumn<{
1909
+ name: "createdAt";
1910
+ tableName: "error_refs";
1911
+ dataType: "date";
1912
+ columnType: "PgTimestamp";
1913
+ data: Date;
1914
+ driverParam: string;
1915
+ notNull: true;
1916
+ hasDefault: true;
1917
+ isPrimaryKey: false;
1918
+ isAutoincrement: false;
1919
+ hasRuntimeDefault: false;
1920
+ enumValues: undefined;
1921
+ baseColumn: never;
1922
+ identity: undefined;
1923
+ generated: undefined;
1924
+ }, {}, {}>;
1925
+ };
1926
+ dialect: "pg";
1927
+ }>;
1836
1928
 
1837
1929
  declare const schema_ActivityActionEnum: typeof ActivityActionEnum;
1838
1930
  declare const schema_RoleEnum: typeof RoleEnum;
@@ -1840,6 +1932,7 @@ declare const schema_accounts: typeof accounts;
1840
1932
  declare const schema_activityLogs: typeof activityLogs;
1841
1933
  declare const schema_authThrottle: typeof authThrottle;
1842
1934
  declare const schema_deviceFingerprints: typeof deviceFingerprints;
1935
+ declare const schema_errorRefs: typeof errorRefs;
1843
1936
  declare const schema_passkeys: typeof passkeys;
1844
1937
  declare const schema_sessions: typeof sessions;
1845
1938
  declare const schema_systemSettings: typeof systemSettings;
@@ -1847,7 +1940,7 @@ declare const schema_twoFactors: typeof twoFactors;
1847
1940
  declare const schema_users: typeof users;
1848
1941
  declare const schema_verifications: typeof verifications;
1849
1942
  declare namespace schema {
1850
- 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_passkeys as passkeys, schema_sessions as sessions, schema_systemSettings as systemSettings, schema_twoFactors as twoFactors, schema_users as users, schema_verifications as verifications };
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 };
1851
1944
  }
1852
1945
 
1853
- export { ActivityActionEnum as A, RoleEnum as R, schema as a, accounts as b, activityLogs as c, authThrottle as d, deviceFingerprints as e, sessions as f, passkeys as p, systemSettings as s, twoFactors as t, users as u, verifications as v };
1946
+ export { ActivityActionEnum as A, RoleEnum as R, schema as a, accounts as b, activityLogs as c, authThrottle as d, deviceFingerprints as e, errorRefs as f, sessions as g, passkeys as p, systemSettings as s, twoFactors as t, users as u, verifications as v };
@@ -1,7 +1,7 @@
1
1
  import * as drizzle_orm from 'drizzle-orm';
2
2
  import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
3
3
 
4
- declare const RoleEnum: drizzle_orm_pg_core.PgEnum<["user", "admin"]>;
4
+ declare const RoleEnum: drizzle_orm_pg_core.PgEnum<["user", "admin", "tester"]>;
5
5
  declare const ActivityActionEnum: drizzle_orm_pg_core.PgEnum<["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"]>;
6
6
  declare const users: drizzle_orm_pg_core.PgTableWithColumns<{
7
7
  name: "user";
@@ -114,14 +114,14 @@ declare const users: drizzle_orm_pg_core.PgTableWithColumns<{
114
114
  tableName: "user";
115
115
  dataType: "string";
116
116
  columnType: "PgEnumColumn";
117
- data: "user" | "admin";
117
+ data: "user" | "admin" | "tester";
118
118
  driverParam: string;
119
119
  notNull: true;
120
120
  hasDefault: true;
121
121
  isPrimaryKey: false;
122
122
  isAutoincrement: false;
123
123
  hasRuntimeDefault: false;
124
- enumValues: ["user", "admin"];
124
+ enumValues: ["user", "admin", "tester"];
125
125
  baseColumn: never;
126
126
  identity: undefined;
127
127
  generated: undefined;
@@ -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: "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";
1145
+ data: "login_failed" | "login" | "logout" | "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;
@@ -1796,6 +1796,23 @@ declare const systemSettings: drizzle_orm_pg_core.PgTableWithColumns<{
1796
1796
  identity: undefined;
1797
1797
  generated: undefined;
1798
1798
  }, {}, {}>;
1799
+ feedbackAttachErrors: drizzle_orm_pg_core.PgColumn<{
1800
+ name: "feedbackAttachErrors";
1801
+ tableName: "system_settings";
1802
+ dataType: "boolean";
1803
+ columnType: "PgBoolean";
1804
+ data: boolean;
1805
+ driverParam: boolean;
1806
+ notNull: true;
1807
+ hasDefault: true;
1808
+ isPrimaryKey: false;
1809
+ isAutoincrement: false;
1810
+ hasRuntimeDefault: false;
1811
+ enumValues: undefined;
1812
+ baseColumn: never;
1813
+ identity: undefined;
1814
+ generated: undefined;
1815
+ }, {}, {}>;
1799
1816
  updatedAt: drizzle_orm_pg_core.PgColumn<{
1800
1817
  name: "updatedAt";
1801
1818
  tableName: "system_settings";
@@ -1833,6 +1850,81 @@ declare const systemSettings: drizzle_orm_pg_core.PgTableWithColumns<{
1833
1850
  };
1834
1851
  dialect: "pg";
1835
1852
  }>;
1853
+ declare const errorRefs: drizzle_orm_pg_core.PgTableWithColumns<{
1854
+ name: "error_refs";
1855
+ schema: undefined;
1856
+ columns: {
1857
+ ref: drizzle_orm_pg_core.PgColumn<{
1858
+ name: "ref";
1859
+ tableName: "error_refs";
1860
+ dataType: "string";
1861
+ columnType: "PgText";
1862
+ data: string;
1863
+ driverParam: string;
1864
+ notNull: true;
1865
+ hasDefault: false;
1866
+ isPrimaryKey: true;
1867
+ isAutoincrement: false;
1868
+ hasRuntimeDefault: false;
1869
+ enumValues: [string, ...string[]];
1870
+ baseColumn: never;
1871
+ identity: undefined;
1872
+ generated: undefined;
1873
+ }, {}, {}>;
1874
+ message: drizzle_orm_pg_core.PgColumn<{
1875
+ name: "message";
1876
+ tableName: "error_refs";
1877
+ dataType: "string";
1878
+ columnType: "PgText";
1879
+ data: string;
1880
+ driverParam: string;
1881
+ notNull: true;
1882
+ hasDefault: false;
1883
+ isPrimaryKey: false;
1884
+ isAutoincrement: false;
1885
+ hasRuntimeDefault: false;
1886
+ enumValues: [string, ...string[]];
1887
+ baseColumn: never;
1888
+ identity: undefined;
1889
+ generated: undefined;
1890
+ }, {}, {}>;
1891
+ detail: drizzle_orm_pg_core.PgColumn<{
1892
+ name: "detail";
1893
+ tableName: "error_refs";
1894
+ dataType: "string";
1895
+ columnType: "PgText";
1896
+ data: string;
1897
+ driverParam: string;
1898
+ notNull: true;
1899
+ hasDefault: false;
1900
+ isPrimaryKey: false;
1901
+ isAutoincrement: false;
1902
+ hasRuntimeDefault: false;
1903
+ enumValues: [string, ...string[]];
1904
+ baseColumn: never;
1905
+ identity: undefined;
1906
+ generated: undefined;
1907
+ }, {}, {}>;
1908
+ createdAt: drizzle_orm_pg_core.PgColumn<{
1909
+ name: "createdAt";
1910
+ tableName: "error_refs";
1911
+ dataType: "date";
1912
+ columnType: "PgTimestamp";
1913
+ data: Date;
1914
+ driverParam: string;
1915
+ notNull: true;
1916
+ hasDefault: true;
1917
+ isPrimaryKey: false;
1918
+ isAutoincrement: false;
1919
+ hasRuntimeDefault: false;
1920
+ enumValues: undefined;
1921
+ baseColumn: never;
1922
+ identity: undefined;
1923
+ generated: undefined;
1924
+ }, {}, {}>;
1925
+ };
1926
+ dialect: "pg";
1927
+ }>;
1836
1928
 
1837
1929
  declare const schema_ActivityActionEnum: typeof ActivityActionEnum;
1838
1930
  declare const schema_RoleEnum: typeof RoleEnum;
@@ -1840,6 +1932,7 @@ declare const schema_accounts: typeof accounts;
1840
1932
  declare const schema_activityLogs: typeof activityLogs;
1841
1933
  declare const schema_authThrottle: typeof authThrottle;
1842
1934
  declare const schema_deviceFingerprints: typeof deviceFingerprints;
1935
+ declare const schema_errorRefs: typeof errorRefs;
1843
1936
  declare const schema_passkeys: typeof passkeys;
1844
1937
  declare const schema_sessions: typeof sessions;
1845
1938
  declare const schema_systemSettings: typeof systemSettings;
@@ -1847,7 +1940,7 @@ declare const schema_twoFactors: typeof twoFactors;
1847
1940
  declare const schema_users: typeof users;
1848
1941
  declare const schema_verifications: typeof verifications;
1849
1942
  declare namespace schema {
1850
- 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_passkeys as passkeys, schema_sessions as sessions, schema_systemSettings as systemSettings, schema_twoFactors as twoFactors, schema_users as users, schema_verifications as verifications };
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 };
1851
1944
  }
1852
1945
 
1853
- export { ActivityActionEnum as A, RoleEnum as R, schema as a, accounts as b, activityLogs as c, authThrottle as d, deviceFingerprints as e, sessions as f, passkeys as p, systemSettings as s, twoFactors as t, users as u, verifications as v };
1946
+ export { ActivityActionEnum as A, RoleEnum as R, schema as a, accounts as b, activityLogs as c, authThrottle as d, deviceFingerprints as e, errorRefs as f, sessions as g, passkeys as p, systemSettings as s, twoFactors as t, users as u, verifications as v };
@@ -25,6 +25,7 @@ __export(schema_exports, {
25
25
  activityLogs: () => activityLogs,
26
26
  authThrottle: () => authThrottle,
27
27
  deviceFingerprints: () => deviceFingerprints,
28
+ errorRefs: () => errorRefs,
28
29
  passkeys: () => passkeys,
29
30
  sessions: () => sessions,
30
31
  systemSettings: () => systemSettings,
@@ -44,7 +45,7 @@ var DEFAULT_MAINTENANCE_EXEMPT_PATHS = [
44
45
  ];
45
46
 
46
47
  // server/db/schema.ts
47
- var RoleEnum = pgCore.pgEnum("roles", ["user", "admin"]);
48
+ var RoleEnum = pgCore.pgEnum("roles", ["user", "admin", "tester"]);
48
49
  var ActivityActionEnum = pgCore.pgEnum("activity_actions", [
49
50
  "login",
50
51
  "logout",
@@ -207,6 +208,9 @@ var systemSettings = pgCore.pgTable("system_settings", {
207
208
  authEnableEmailPassword: pgCore.boolean("authEnableEmailPassword").notNull().default(true),
208
209
  authEnableOneTap: pgCore.boolean("authEnableOneTap").notNull().default(false),
209
210
  enableSessionRevocation: pgCore.boolean("enableSessionRevocation").notNull().default(true),
211
+ // Attach the error a user hit to feedback they send from it (see
212
+ // lib/feedback-route.ts). Off = only what the user typed is sent.
213
+ feedbackAttachErrors: pgCore.boolean("feedbackAttachErrors").notNull().default(true),
210
214
  updatedAt: pgCore.timestamp("updatedAt").notNull().defaultNow(),
211
215
  // Who last changed a setting. This row doesn't "belong" to that admin the
212
216
  // way sessions/activityLogs belong to their user, so deleting that admin's
@@ -215,15 +219,31 @@ var systemSettings = pgCore.pgTable("system_settings", {
215
219
  }, (table) => [
216
220
  pgCore.check("system_settings_singleton", drizzleOrm.sql`${table.id} = 'default'`)
217
221
  ]);
222
+ var errorRefs = pgCore.pgTable("error_refs", {
223
+ ref: pgCore.text("ref").primaryKey(),
224
+ message: pgCore.text("message").notNull(),
225
+ detail: pgCore.text("detail").notNull(),
226
+ createdAt: pgCore.timestamp("createdAt").notNull().defaultNow()
227
+ }, (table) => [
228
+ pgCore.index("error_refs_created_at_idx").on(table.createdAt)
229
+ ]);
218
230
  var envSchema = zod.z.object({
219
231
  NODE_ENV: zod.z.enum(["development", "production", "test"]).default("development"),
220
232
  PORT: zod.z.string().default("3000").transform(Number),
221
233
  DATABASE_URL: zod.z.string().default(""),
222
234
  RESEND_API_KEY: zod.z.string().default(""),
235
+ // Sender for every transactional email. Must be on a domain verified in
236
+ // your Resend account.
237
+ EMAIL_FROM: zod.z.string().default("Acme <onboarding@xavierkhew.xyz>"),
223
238
  // Display name for this deployment — shown as the authenticator-app label
224
239
  // (2FA issuer) and the passkey relying-party name. Consuming projects set
225
240
  // this in their own .env; defaults to the template name.
226
241
  APP_NAME: zod.z.string().default("Next.js Template"),
242
+ // Where the dashboard feedback form delivers (app/api/feedback). Set either
243
+ // or both; with neither, the Feedback button is hidden. FEEDBACK_EMAIL takes
244
+ // a comma-separated list and sends through Resend (needs RESEND_API_KEY).
245
+ FEEDBACK_DISCORD_WEBHOOK_URL: zod.z.string().default(""),
246
+ FEEDBACK_EMAIL: zod.z.string().default(""),
227
247
  // Seed-only: the live value lives in the system_settings DB row (see
228
248
  // lib/settings-queries.ts) once it's been seeded on first read, and is
229
249
  // changed from the admin System Settings page, not by editing this var.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../server/db/schema.ts","../../lib/maintenance.ts","../../config/env-schema.ts","../../config/env.ts","../../server/db/index.ts","../../lib/session-queries.ts"],"names":["pgEnum","pgTable","text","createId","boolean","timestamp","integer","unique","check","sql","z","Pool","drizzlePg","neon","drizzle","eq","desc"],"mappings":"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","file":"queries.js","sourcesContent":["import { boolean, check, integer, pgEnum, pgTable, text, timestamp, unique } from \"drizzle-orm/pg-core\";\nimport { sql } from \"drizzle-orm\";\nimport { createId } from '@paralleldrive/cuid2'\nimport { DEFAULT_MAINTENANCE_EXEMPT_PATHS } from \"../../lib/maintenance\";\n\nexport const RoleEnum = pgEnum('roles', ['user', 'admin'])\n\nexport const ActivityActionEnum = pgEnum('activity_actions', [\n 'login',\n 'logout',\n 'login_failed',\n 'password_changed',\n 'email_changed',\n 'profile_updated',\n 'session_revoked',\n 'user_deleted',\n 'user_banned',\n 'user_unbanned',\n 'role_changed',\n 'impersonation_started',\n 'impersonation_stopped',\n 'settings_changed',\n 'passkey_added',\n 'passkey_removed',\n])\n\nexport const users = pgTable(\"user\", {\n id: text(\"id\").notNull().primaryKey().$defaultFn(() => createId()),\n name: text('name').notNull(),\n email: text('email').notNull().unique(),\n password: text('password'),\n emailVerified: boolean(\"emailVerified\").notNull().default(false),\n image: text(\"image\"),\n role: RoleEnum('roles').default('user').notNull(),\n banned: boolean('banned').default(false).notNull(),\n bannedAt: timestamp('bannedAt'),\n bannedReason: text('bannedReason'),\n // Required by better-auth's admin plugin schema (auto-expiring bans). We\n // never set this ourselves, so it stays null and bans behave as permanent,\n // same as before the plugin was added.\n banExpires: timestamp('banExpires'),\n lastLoginAt: timestamp('lastLoginAt'),\n lastActiveAt: timestamp('lastActiveAt'),\n // Set by better-auth's twoFactor plugin — true once the user has\n // completed TOTP setup (see twoFactor pgTable below for the secret /\n // backup codes themselves).\n twoFactorEnabled: boolean('twoFactorEnabled').notNull().default(false),\n createdAt: timestamp('createdAt').notNull().defaultNow(),\n updatedAt: timestamp('updatedAt').notNull().defaultNow(),\n});\n\nexport const sessions = pgTable(\"session\", {\n id: text(\"id\").notNull().primaryKey().$defaultFn(() => createId()),\n expiresAt: timestamp(\"expiresAt\").notNull(),\n token: text(\"token\").notNull().unique(),\n createdAt: timestamp(\"createdAt\").notNull().defaultNow(),\n updatedAt: timestamp(\"updatedAt\").notNull().defaultNow(),\n ipAddress: text(\"ipAddress\"),\n userAgent: text(\"userAgent\"),\n userId: text(\"userId\")\n .notNull()\n .references(() => users.id, { onDelete: \"cascade\" }),\n // Set by better-auth's admin plugin while this session is an admin\n // impersonating another user; holds the impersonating admin's user id.\n impersonatedBy: text(\"impersonatedBy\"),\n});\n\nexport const accounts = pgTable(\"account\", {\n id: text(\"id\").notNull().primaryKey().$defaultFn(() => createId()),\n accountId: text(\"accountId\").notNull(),\n providerId: text(\"providerId\").notNull(),\n userId: text(\"userId\")\n .notNull()\n .references(() => users.id, { onDelete: \"cascade\" }),\n accessToken: text(\"accessToken\"),\n refreshToken: text(\"refreshToken\"),\n idToken: text(\"idToken\"),\n accessTokenExpiresAt: timestamp(\"accessTokenExpiresAt\"),\n refreshTokenExpiresAt: timestamp(\"refreshTokenExpiresAt\"),\n scope: text(\"scope\"),\n password: text(\"password\"),\n createdAt: timestamp(\"createdAt\").notNull().defaultNow(),\n updatedAt: timestamp(\"updatedAt\").notNull().defaultNow(),\n});\n\n// Better-auth's twoFactor plugin. One row per user (created on first\n// `enable`); secret and backupCodes are its own encrypted-at-rest strings,\n// field names/types must match its expectations exactly (drizzleAdapter in\n// server/auth.ts maps this table to the plugin's \"twoFactor\" model as-is).\nexport const twoFactors = pgTable(\"twoFactor\", {\n id: text(\"id\").notNull().primaryKey().$defaultFn(() => createId()),\n secret: text(\"secret\").notNull(),\n backupCodes: text(\"backupCodes\").notNull(),\n userId: text(\"userId\")\n .notNull()\n .references(() => users.id, { onDelete: \"cascade\" }),\n // Added in better-auth 1.7 (TOTP lockout). Defaults match the plugin's.\n verified: boolean(\"verified\").default(true),\n failedVerificationCount: integer(\"failedVerificationCount\").default(0),\n lockedUntil: timestamp(\"lockedUntil\"),\n});\n\n// Better-auth's passkey plugin — one row per registered WebAuthn credential.\nexport const passkeys = pgTable(\"passkey\", {\n id: text(\"id\").notNull().primaryKey().$defaultFn(() => createId()),\n name: text(\"name\"),\n publicKey: text(\"publicKey\").notNull(),\n userId: text(\"userId\")\n .notNull()\n .references(() => users.id, { onDelete: \"cascade\" }),\n credentialID: text(\"credentialID\").notNull().unique(),\n counter: integer(\"counter\").notNull(),\n deviceType: text(\"deviceType\").notNull(),\n backedUp: boolean(\"backedUp\").notNull(),\n transports: text(\"transports\"),\n createdAt: timestamp(\"createdAt\"),\n aaguid: text(\"aaguid\"),\n});\n\nexport const verifications = pgTable(\"verification\", {\n id: text(\"id\").notNull().primaryKey().$defaultFn(() => createId()),\n identifier: text(\"identifier\").notNull(),\n value: text(\"value\").notNull(),\n expiresAt: timestamp(\"expiresAt\").notNull(),\n createdAt: timestamp(\"createdAt\").notNull().defaultNow(),\n updatedAt: timestamp(\"updatedAt\").notNull().defaultNow(),\n});\n\nexport const activityLogs = pgTable(\"activity_log\", {\n id: text(\"id\").notNull().primaryKey().$defaultFn(() => createId()),\n userId: text(\"userId\")\n .notNull()\n .references(() => users.id, { onDelete: \"cascade\" }),\n action: ActivityActionEnum('action').notNull(),\n description: text('description').notNull(),\n ipAddress: text('ipAddress'),\n userAgent: text('userAgent'),\n metadata: text('metadata'),\n // Populated on 'login' events only (registration + sign-in) — parsed from\n // userAgent/ipAddress at write time so the record stays stable even if\n // the parsing library or geoip database changes later.\n referrerUrl: text('referrerUrl'),\n os: text('os'),\n browser: text('browser'),\n deviceType: text('deviceType'),\n country: text('country'),\n city: text('city'),\n createdAt: timestamp('createdAt').notNull().defaultNow(),\n});\n\n// One row per (user, device fingerprint) pair. Its only job is to answer\n// \"has this account signed in from this device before?\" — no matching row ⇒\n// send a new-device alert (see app/api/device-check/route.ts). visitorId is\n// FingerprintJS's identifier, computed client-side in\n// components/auth/deviceCheck.tsx. UA+IP are deliberately NOT the signal here:\n// they churn constantly on mobile and would alert on every other login.\nexport const deviceFingerprints = pgTable(\"device_fingerprint\", {\n id: text(\"id\").notNull().primaryKey().$defaultFn(() => createId()),\n userId: text(\"userId\")\n .notNull()\n .references(() => users.id, { onDelete: \"cascade\" }),\n visitorId: text(\"visitorId\").notNull(),\n // Context captured at first-seen time — for the admin panel's \"New devices\"\n // card and the alert email. Not part of the new-vs-known decision (that's\n // visitorId only), just so an admin can eyeball whether a sign-in looks like\n // a hijack. Nullable: an old row predates these columns, or geoip missed.\n ipAddress: text(\"ipAddress\"),\n userAgent: text(\"userAgent\"),\n country: text(\"country\"),\n city: text(\"city\"),\n createdAt: timestamp(\"createdAt\").notNull().defaultNow(),\n}, (table) => [\n unique(\"device_fingerprint_user_visitor\").on(table.userId, table.visitorId),\n]);\n\n// Per-device abuse throttle for /sign-in/email and /sign-up/email — one\n// fixed-window counter row per FingerprintJS visitorId (sent by the auth\n// forms as the x-device-fingerprint header; see lib/auth-throttle.ts).\n// Keyed by device, not IP: IP is shared behind corporate NAT / CGNAT / VPN,\n// so an IP counter throttles coworkers together while missing an abuser who\n// rotates IPs. Rows whose window has elapsed are dead weight but harmless\n// (reset on the next attempt) — prune on a cron if the table ever grows.\nexport const authThrottle = pgTable(\"auth_throttle\", {\n fingerprint: text(\"fingerprint\").notNull().primaryKey(),\n count: integer(\"count\").notNull().default(0),\n windowStart: timestamp(\"windowStart\").notNull().defaultNow(),\n // Blockable data points, overwritten on every attempt (last-write-wins) so\n // the admin panel can show who to block — by IP or by fingerprint — with no\n // join and no per-attempt history table. windowStart anchors the counter's\n // window; lastAttemptAt is just \"most recently seen\".\n lastAttemptAt: timestamp(\"lastAttemptAt\").notNull().defaultNow(),\n ipAddress: text(\"ipAddress\"),\n userAgent: text(\"userAgent\"),\n lastEmail: text(\"lastEmail\"),\n lastKind: text(\"lastKind\"), // 'signin' | 'signup'\n});\n\n// Singleton row (id is always 'default') holding admin-editable settings for\n// config that used to be env-var-only. See lib/settings-queries.ts for the\n// cached read path and lazy-seed-from-env behavior.\nexport const systemSettings = pgTable(\"system_settings\", {\n id: text(\"id\").primaryKey().default(\"default\"),\n maintenanceMode: boolean(\"maintenanceMode\").notNull().default(false),\n maintenanceMessage: text(\"maintenanceMessage\"),\n // Path prefixes that stay reachable while maintenance mode is on (see\n // lib/maintenance.ts — a few auth paths are always open on top of these).\n maintenanceExemptPaths: text(\"maintenanceExemptPaths\").array().notNull().default(DEFAULT_MAINTENANCE_EXEMPT_PATHS),\n authEnableGoogle: boolean(\"authEnableGoogle\").notNull().default(true),\n authEnableEmailPassword: boolean(\"authEnableEmailPassword\").notNull().default(true),\n authEnableOneTap: boolean(\"authEnableOneTap\").notNull().default(false),\n enableSessionRevocation: boolean(\"enableSessionRevocation\").notNull().default(true),\n updatedAt: timestamp(\"updatedAt\").notNull().defaultNow(),\n // Who last changed a setting. This row doesn't \"belong\" to that admin the\n // way sessions/activityLogs belong to their user, so deleting that admin's\n // account should null this out rather than cascade-delete the singleton row.\n updatedBy: text(\"updatedBy\").references(() => users.id, { onDelete: \"set null\" }),\n}, (table) => [\n check(\"system_settings_singleton\", sql`${table.id} = 'default'`),\n]);","// Pure path logic for maintenance mode — no DB / server-only imports, so it\n// can run in proxy.ts and in the admin form alike.\n\n// Default for the admin-editable exempt list: the public marketing pages.\nexport const DEFAULT_MAINTENANCE_EXEMPT_PATHS = [\n \"/\",\n \"/features\",\n \"/changelog\",\n \"/changelog-template\",\n \"/privacy\",\n \"/terms\",\n]\n\n// Always reachable, whatever the admin saves — otherwise an admin could\n// lock themselves out of the sign-in flow needed to turn maintenance off.\nexport const ALWAYS_OPEN_PATHS = [\n \"/maintenance\",\n \"/login\", // includes /login/2fa\n \"/forgot-password\",\n \"/reset-password\",\n \"/api/auth\",\n \"/api/settings/public\", // login page reads the One Tap flag from here\n]\n\n// `/foo` matches `/foo` and `/foo/...` but not `/foobar`; `/` matches only `/`.\nfunction matches(pathname: string, prefix: string) {\n const p = prefix.length > 1 ? prefix.replace(/\\/+$/, \"\") : prefix\n return pathname === p || (p !== \"/\" && pathname.startsWith(p + \"/\"))\n}\n\nexport function isMaintenanceExempt(pathname: string, exemptPaths: string[]) {\n return [...ALWAYS_OPEN_PATHS, ...exemptPaths].some((p) => matches(pathname, p))\n}\n","// 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 // 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 // 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';\n\n// neon-http driver for production\nimport { neon } from '@neondatabase/serverless';\nimport { drizzle } from 'drizzle-orm/neon-http';\n\n// postgres driver for local development\nimport { drizzle as drizzlePg } from 'drizzle-orm/node-postgres';\nimport { Pool } from 'pg';\n\nimport * as schema from './schema';\nimport { config } from '../../config/env';\n\n// Import the query builder\nimport { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\nimport { NeonHttpDatabase } from 'drizzle-orm/neon-http';\n\ntype DrizzleNeon = NeonHttpDatabase<typeof schema>;\ntype DrizzlePg = PostgresJsDatabase<typeof schema>;\n\nlet db: DrizzleNeon | DrizzlePg\n\n\nif (config.DB_DRIVER === 'pg') {\n const pool = new Pool({\n connectionString: config.DATABASE_URL!,\n ssl: config.DATABASE_SSL ? { rejectUnauthorized: false } : undefined,\n });\n db = drizzlePg(pool, {\n schema,\n logger: true,\n });\n\n console.log('🟡 Using PostgreSQL (pg) driver');\n\n} else if (config.DB_DRIVER === 'neon') {\n const sql = neon(config.DATABASE_URL!);\n db = drizzle(sql, { schema, logger: true });\n\n console.log('🟢 Using Neon (HTTP) driver');\n\n} else {\n console.log('Database connection not established, unknown DB_DRIVER:', config.DB_DRIVER);\n}\n// Note: In production, you might want to disable logging or use a more sophisticated logger.\n\nexport { db }","import \"server-only\"\nimport { db } from \"../server/db\"\nimport { sessions } from \"../server/db/schema\"\nimport { eq, desc } from \"drizzle-orm\"\n\n/**\n * Get all active sessions for a user\n */\nexport async function getUserSessions(userId: string) {\n return await db\n .select()\n .from(sessions)\n .where(eq(sessions.userId, userId))\n .orderBy(desc(sessions.createdAt))\n}\n\n/**\n * Get current session info by token\n */\nexport async function getSessionByToken(token: string) {\n const result = await db\n .select()\n .from(sessions)\n .where(eq(sessions.token, token))\n .limit(1)\n\n return result[0] || null\n}\n\n/**\n * Count active sessions for user\n */\nexport async function countUserSessions(userId: string): Promise<number> {\n const userSessions = await getUserSessions(userId)\n\n // Filter out expired sessions\n const now = new Date()\n return userSessions.filter(s => s.expiresAt > now).length\n}\n"]}
1
+ {"version":3,"sources":["../../server/db/schema.ts","../../lib/maintenance.ts","../../config/env-schema.ts","../../config/env.ts","../../server/db/index.ts","../../lib/session-queries.ts"],"names":["pgEnum","pgTable","text","createId","boolean","timestamp","integer","unique","check","sql","index","z","Pool","drizzlePg","neon","drizzle","eq","desc"],"mappings":"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","file":"queries.js","sourcesContent":["import { boolean, check, index, integer, pgEnum, pgTable, text, timestamp, unique } from \"drizzle-orm/pg-core\";\nimport { sql } from \"drizzle-orm\";\nimport { createId } from '@paralleldrive/cuid2'\nimport { DEFAULT_MAINTENANCE_EXEMPT_PATHS } from \"../../lib/maintenance\";\n\n// 'tester' is a regular user account flagged for testing; apps can use it to\n// keep test accounts apart from real users. It has no admin access.\nexport const RoleEnum = pgEnum('roles', ['user', 'admin', 'tester'])\n\nexport const ActivityActionEnum = pgEnum('activity_actions', [\n 'login',\n 'logout',\n 'login_failed',\n 'password_changed',\n 'email_changed',\n 'profile_updated',\n 'session_revoked',\n 'user_deleted',\n 'user_banned',\n 'user_unbanned',\n 'role_changed',\n 'impersonation_started',\n 'impersonation_stopped',\n 'settings_changed',\n 'passkey_added',\n 'passkey_removed',\n])\n\nexport const users = pgTable(\"user\", {\n id: text(\"id\").notNull().primaryKey().$defaultFn(() => createId()),\n name: text('name').notNull(),\n email: text('email').notNull().unique(),\n password: text('password'),\n emailVerified: boolean(\"emailVerified\").notNull().default(false),\n image: text(\"image\"),\n role: RoleEnum('roles').default('user').notNull(),\n banned: boolean('banned').default(false).notNull(),\n bannedAt: timestamp('bannedAt'),\n bannedReason: text('bannedReason'),\n // Required by better-auth's admin plugin schema (auto-expiring bans). We\n // never set this ourselves, so it stays null and bans behave as permanent,\n // same as before the plugin was added.\n banExpires: timestamp('banExpires'),\n lastLoginAt: timestamp('lastLoginAt'),\n lastActiveAt: timestamp('lastActiveAt'),\n // Set by better-auth's twoFactor plugin — true once the user has\n // completed TOTP setup (see twoFactor pgTable below for the secret /\n // backup codes themselves).\n twoFactorEnabled: boolean('twoFactorEnabled').notNull().default(false),\n createdAt: timestamp('createdAt').notNull().defaultNow(),\n updatedAt: timestamp('updatedAt').notNull().defaultNow(),\n});\n\nexport const sessions = pgTable(\"session\", {\n id: text(\"id\").notNull().primaryKey().$defaultFn(() => createId()),\n expiresAt: timestamp(\"expiresAt\").notNull(),\n token: text(\"token\").notNull().unique(),\n createdAt: timestamp(\"createdAt\").notNull().defaultNow(),\n updatedAt: timestamp(\"updatedAt\").notNull().defaultNow(),\n ipAddress: text(\"ipAddress\"),\n userAgent: text(\"userAgent\"),\n userId: text(\"userId\")\n .notNull()\n .references(() => users.id, { onDelete: \"cascade\" }),\n // Set by better-auth's admin plugin while this session is an admin\n // impersonating another user; holds the impersonating admin's user id.\n impersonatedBy: text(\"impersonatedBy\"),\n});\n\nexport const accounts = pgTable(\"account\", {\n id: text(\"id\").notNull().primaryKey().$defaultFn(() => createId()),\n accountId: text(\"accountId\").notNull(),\n providerId: text(\"providerId\").notNull(),\n userId: text(\"userId\")\n .notNull()\n .references(() => users.id, { onDelete: \"cascade\" }),\n accessToken: text(\"accessToken\"),\n refreshToken: text(\"refreshToken\"),\n idToken: text(\"idToken\"),\n accessTokenExpiresAt: timestamp(\"accessTokenExpiresAt\"),\n refreshTokenExpiresAt: timestamp(\"refreshTokenExpiresAt\"),\n scope: text(\"scope\"),\n password: text(\"password\"),\n createdAt: timestamp(\"createdAt\").notNull().defaultNow(),\n updatedAt: timestamp(\"updatedAt\").notNull().defaultNow(),\n});\n\n// Better-auth's twoFactor plugin. One row per user (created on first\n// `enable`); secret and backupCodes are its own encrypted-at-rest strings,\n// field names/types must match its expectations exactly (drizzleAdapter in\n// server/auth.ts maps this table to the plugin's \"twoFactor\" model as-is).\nexport const twoFactors = pgTable(\"twoFactor\", {\n id: text(\"id\").notNull().primaryKey().$defaultFn(() => createId()),\n secret: text(\"secret\").notNull(),\n backupCodes: text(\"backupCodes\").notNull(),\n userId: text(\"userId\")\n .notNull()\n .references(() => users.id, { onDelete: \"cascade\" }),\n // Added in better-auth 1.7 (TOTP lockout). Defaults match the plugin's.\n verified: boolean(\"verified\").default(true),\n failedVerificationCount: integer(\"failedVerificationCount\").default(0),\n lockedUntil: timestamp(\"lockedUntil\"),\n});\n\n// Better-auth's passkey plugin — one row per registered WebAuthn credential.\nexport const passkeys = pgTable(\"passkey\", {\n id: text(\"id\").notNull().primaryKey().$defaultFn(() => createId()),\n name: text(\"name\"),\n publicKey: text(\"publicKey\").notNull(),\n userId: text(\"userId\")\n .notNull()\n .references(() => users.id, { onDelete: \"cascade\" }),\n credentialID: text(\"credentialID\").notNull().unique(),\n counter: integer(\"counter\").notNull(),\n deviceType: text(\"deviceType\").notNull(),\n backedUp: boolean(\"backedUp\").notNull(),\n transports: text(\"transports\"),\n createdAt: timestamp(\"createdAt\"),\n aaguid: text(\"aaguid\"),\n});\n\nexport const verifications = pgTable(\"verification\", {\n id: text(\"id\").notNull().primaryKey().$defaultFn(() => createId()),\n identifier: text(\"identifier\").notNull(),\n value: text(\"value\").notNull(),\n expiresAt: timestamp(\"expiresAt\").notNull(),\n createdAt: timestamp(\"createdAt\").notNull().defaultNow(),\n updatedAt: timestamp(\"updatedAt\").notNull().defaultNow(),\n});\n\nexport const activityLogs = pgTable(\"activity_log\", {\n id: text(\"id\").notNull().primaryKey().$defaultFn(() => createId()),\n userId: text(\"userId\")\n .notNull()\n .references(() => users.id, { onDelete: \"cascade\" }),\n action: ActivityActionEnum('action').notNull(),\n description: text('description').notNull(),\n ipAddress: text('ipAddress'),\n userAgent: text('userAgent'),\n metadata: text('metadata'),\n // Populated on 'login' events only (registration + sign-in) — parsed from\n // userAgent/ipAddress at write time so the record stays stable even if\n // the parsing library or geoip database changes later.\n referrerUrl: text('referrerUrl'),\n os: text('os'),\n browser: text('browser'),\n deviceType: text('deviceType'),\n country: text('country'),\n city: text('city'),\n createdAt: timestamp('createdAt').notNull().defaultNow(),\n});\n\n// One row per (user, device fingerprint) pair. Its only job is to answer\n// \"has this account signed in from this device before?\" — no matching row ⇒\n// send a new-device alert (see app/api/device-check/route.ts). visitorId is\n// FingerprintJS's identifier, computed client-side in\n// components/auth/deviceCheck.tsx. UA+IP are deliberately NOT the signal here:\n// they churn constantly on mobile and would alert on every other login.\nexport const deviceFingerprints = pgTable(\"device_fingerprint\", {\n id: text(\"id\").notNull().primaryKey().$defaultFn(() => createId()),\n userId: text(\"userId\")\n .notNull()\n .references(() => users.id, { onDelete: \"cascade\" }),\n visitorId: text(\"visitorId\").notNull(),\n // Context captured at first-seen time — for the admin panel's \"New devices\"\n // card and the alert email. Not part of the new-vs-known decision (that's\n // visitorId only), just so an admin can eyeball whether a sign-in looks like\n // a hijack. Nullable: an old row predates these columns, or geoip missed.\n ipAddress: text(\"ipAddress\"),\n userAgent: text(\"userAgent\"),\n country: text(\"country\"),\n city: text(\"city\"),\n createdAt: timestamp(\"createdAt\").notNull().defaultNow(),\n}, (table) => [\n unique(\"device_fingerprint_user_visitor\").on(table.userId, table.visitorId),\n]);\n\n// Per-device abuse throttle for /sign-in/email and /sign-up/email — one\n// fixed-window counter row per FingerprintJS visitorId (sent by the auth\n// forms as the x-device-fingerprint header; see lib/auth-throttle.ts).\n// Keyed by device, not IP: IP is shared behind corporate NAT / CGNAT / VPN,\n// so an IP counter throttles coworkers together while missing an abuser who\n// rotates IPs. Rows whose window has elapsed are dead weight but harmless\n// (reset on the next attempt) — prune on a cron if the table ever grows.\nexport const authThrottle = pgTable(\"auth_throttle\", {\n fingerprint: text(\"fingerprint\").notNull().primaryKey(),\n count: integer(\"count\").notNull().default(0),\n windowStart: timestamp(\"windowStart\").notNull().defaultNow(),\n // Blockable data points, overwritten on every attempt (last-write-wins) so\n // the admin panel can show who to block — by IP or by fingerprint — with no\n // join and no per-attempt history table. windowStart anchors the counter's\n // window; lastAttemptAt is just \"most recently seen\".\n lastAttemptAt: timestamp(\"lastAttemptAt\").notNull().defaultNow(),\n ipAddress: text(\"ipAddress\"),\n userAgent: text(\"userAgent\"),\n lastEmail: text(\"lastEmail\"),\n lastKind: text(\"lastKind\"), // 'signin' | 'signup'\n});\n\n// Singleton row (id is always 'default') holding admin-editable settings for\n// config that used to be env-var-only. See lib/settings-queries.ts for the\n// cached read path and lazy-seed-from-env behavior.\nexport const systemSettings = pgTable(\"system_settings\", {\n id: text(\"id\").primaryKey().default(\"default\"),\n maintenanceMode: boolean(\"maintenanceMode\").notNull().default(false),\n maintenanceMessage: text(\"maintenanceMessage\"),\n // Path prefixes that stay reachable while maintenance mode is on (see\n // lib/maintenance.ts — a few auth paths are always open on top of these).\n maintenanceExemptPaths: text(\"maintenanceExemptPaths\").array().notNull().default(DEFAULT_MAINTENANCE_EXEMPT_PATHS),\n authEnableGoogle: boolean(\"authEnableGoogle\").notNull().default(true),\n authEnableEmailPassword: boolean(\"authEnableEmailPassword\").notNull().default(true),\n authEnableOneTap: boolean(\"authEnableOneTap\").notNull().default(false),\n enableSessionRevocation: boolean(\"enableSessionRevocation\").notNull().default(true),\n // Attach the error a user hit to feedback they send from it (see\n // lib/feedback-route.ts). Off = only what the user typed is sent.\n feedbackAttachErrors: boolean(\"feedbackAttachErrors\").notNull().default(true),\n updatedAt: timestamp(\"updatedAt\").notNull().defaultNow(),\n // Who last changed a setting. This row doesn't \"belong\" to that admin the\n // way sessions/activityLogs belong to their user, so deleting that admin's\n // account should null this out rather than cascade-delete the singleton row.\n updatedBy: text(\"updatedBy\").references(() => users.id, { onDelete: \"set null\" }),\n}, (table) => [\n check(\"system_settings_singleton\", sql`${table.id} = 'default'`),\n]);\n// Technical detail of unexpected errors, keyed by the short ref the user sees\n// (\"... (ref: K7Q2PX)\", see lib/errors.ts). Never sent to the browser: the\n// feedback route looks a ref up and attaches the detail to the report it\n// sends to Discord/email. Rows older than 30 days are pruned on insert.\nexport const errorRefs = pgTable(\"error_refs\", {\n ref: text(\"ref\").primaryKey(),\n message: text(\"message\").notNull(),\n detail: text(\"detail\").notNull(),\n createdAt: timestamp(\"createdAt\").notNull().defaultNow(),\n}, (table) => [\n index(\"error_refs_created_at_idx\").on(table.createdAt),\n]);\n","// Pure path logic for maintenance mode — no DB / server-only imports, so it\n// can run in proxy.ts and in the admin form alike.\n\n// Default for the admin-editable exempt list: the public marketing pages.\nexport const DEFAULT_MAINTENANCE_EXEMPT_PATHS = [\n \"/\",\n \"/features\",\n \"/changelog\",\n \"/changelog-template\",\n \"/privacy\",\n \"/terms\",\n]\n\n// Always reachable, whatever the admin saves — otherwise an admin could\n// lock themselves out of the sign-in flow needed to turn maintenance off.\nexport const ALWAYS_OPEN_PATHS = [\n \"/maintenance\",\n \"/login\", // includes /login/2fa\n \"/forgot-password\",\n \"/reset-password\",\n \"/api/auth\",\n \"/api/settings/public\", // login page reads the One Tap flag from here\n]\n\n// `/foo` matches `/foo` and `/foo/...` but not `/foobar`; `/` matches only `/`.\nfunction matches(pathname: string, prefix: string) {\n const p = prefix.length > 1 ? prefix.replace(/\\/+$/, \"\") : prefix\n return pathname === p || (p !== \"/\" && pathname.startsWith(p + \"/\"))\n}\n\nexport function isMaintenanceExempt(pathname: string, exemptPaths: string[]) {\n return [...ALWAYS_OPEN_PATHS, ...exemptPaths].some((p) => matches(pathname, p))\n}\n","// 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 // 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';\n\n// neon-http driver for production\nimport { neon } from '@neondatabase/serverless';\nimport { drizzle } from 'drizzle-orm/neon-http';\n\n// postgres driver for local development\nimport { drizzle as drizzlePg } from 'drizzle-orm/node-postgres';\nimport { Pool } from 'pg';\n\nimport * as schema from './schema';\nimport { config } from '../../config/env';\n\n// Import the query builder\nimport { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\nimport { NeonHttpDatabase } from 'drizzle-orm/neon-http';\n\ntype DrizzleNeon = NeonHttpDatabase<typeof schema>;\ntype DrizzlePg = PostgresJsDatabase<typeof schema>;\n\nlet db: DrizzleNeon | DrizzlePg\n\n\nif (config.DB_DRIVER === 'pg') {\n const pool = new Pool({\n connectionString: config.DATABASE_URL!,\n ssl: config.DATABASE_SSL ? { rejectUnauthorized: false } : undefined,\n });\n db = drizzlePg(pool, {\n schema,\n logger: true,\n });\n\n console.log('🟡 Using PostgreSQL (pg) driver');\n\n} else if (config.DB_DRIVER === 'neon') {\n const sql = neon(config.DATABASE_URL!);\n db = drizzle(sql, { schema, logger: true });\n\n console.log('🟢 Using Neon (HTTP) driver');\n\n} else {\n console.log('Database connection not established, unknown DB_DRIVER:', config.DB_DRIVER);\n}\n// Note: In production, you might want to disable logging or use a more sophisticated logger.\n\nexport { db }","import \"server-only\"\nimport { db } from \"../server/db\"\nimport { sessions } from \"../server/db/schema\"\nimport { eq, desc } from \"drizzle-orm\"\n\n/**\n * Get all active sessions for a user\n */\nexport async function getUserSessions(userId: string) {\n return await db\n .select()\n .from(sessions)\n .where(eq(sessions.userId, userId))\n .orderBy(desc(sessions.createdAt))\n}\n\n/**\n * Get current session info by token\n */\nexport async function getSessionByToken(token: string) {\n const result = await db\n .select()\n .from(sessions)\n .where(eq(sessions.token, token))\n .limit(1)\n\n return result[0] || null\n}\n\n/**\n * Count active sessions for user\n */\nexport async function countUserSessions(userId: string): Promise<number> {\n const userSessions = await getUserSessions(userId)\n\n // Filter out expired sessions\n const now = new Date()\n return userSessions.filter(s => s.expiresAt > now).length\n}\n"]}
@@ -1,6 +1,6 @@
1
- import { db } from '../chunk-5PYDAD4P.mjs';
2
- import { sessions } from '../chunk-4B7MJOLH.mjs';
3
- import '../chunk-GTPTVNY2.mjs';
1
+ import { db } from '../chunk-WZDAMCUX.mjs';
2
+ import { sessions } from '../chunk-ZQCALTKB.mjs';
3
+ import '../chunk-TMJYAOC2.mjs';
4
4
  import '../chunk-3465SI5N.mjs';
5
5
  import 'server-only';
6
6
  import { eq, desc } from 'drizzle-orm';
@@ -1,11 +1,11 @@
1
- import { s as systemSettings } from '../schema-BghJ8N4X.mjs';
1
+ import { s as systemSettings } from '../schema-BNSBWNjK.mjs';
2
2
  import 'drizzle-orm';
3
3
  import 'drizzle-orm/pg-core';
4
4
 
5
5
  type SystemSettings = typeof systemSettings.$inferSelect;
6
6
  declare function getSystemSettings(): Promise<SystemSettings>;
7
7
  declare function invalidateSystemSettingsCache(): void;
8
- type SystemSettingsPatch = Partial<Pick<SystemSettings, 'maintenanceMode' | 'maintenanceMessage' | 'maintenanceExemptPaths' | 'authEnableGoogle' | 'authEnableEmailPassword' | 'authEnableOneTap' | 'enableSessionRevocation'>>;
8
+ type SystemSettingsPatch = Partial<Pick<SystemSettings, 'maintenanceMode' | 'maintenanceMessage' | 'maintenanceExemptPaths' | 'authEnableGoogle' | 'authEnableEmailPassword' | 'authEnableOneTap' | 'enableSessionRevocation' | 'feedbackAttachErrors'>>;
9
9
  declare function updateSystemSettings(patch: SystemSettingsPatch, updatedBy: string): Promise<SystemSettings>;
10
10
  declare function getEffectiveAuthFlags(): Promise<{
11
11
  google: boolean;
@@ -1,11 +1,11 @@
1
- import { s as systemSettings } from '../schema-BghJ8N4X.js';
1
+ import { s as systemSettings } from '../schema-BNSBWNjK.js';
2
2
  import 'drizzle-orm';
3
3
  import 'drizzle-orm/pg-core';
4
4
 
5
5
  type SystemSettings = typeof systemSettings.$inferSelect;
6
6
  declare function getSystemSettings(): Promise<SystemSettings>;
7
7
  declare function invalidateSystemSettingsCache(): void;
8
- type SystemSettingsPatch = Partial<Pick<SystemSettings, 'maintenanceMode' | 'maintenanceMessage' | 'maintenanceExemptPaths' | 'authEnableGoogle' | 'authEnableEmailPassword' | 'authEnableOneTap' | 'enableSessionRevocation'>>;
8
+ type SystemSettingsPatch = Partial<Pick<SystemSettings, 'maintenanceMode' | 'maintenanceMessage' | 'maintenanceExemptPaths' | 'authEnableGoogle' | 'authEnableEmailPassword' | 'authEnableOneTap' | 'enableSessionRevocation' | 'feedbackAttachErrors'>>;
9
9
  declare function updateSystemSettings(patch: SystemSettingsPatch, updatedBy: string): Promise<SystemSettings>;
10
10
  declare function getEffectiveAuthFlags(): Promise<{
11
11
  google: boolean;
@@ -43,6 +43,7 @@ __export(schema_exports, {
43
43
  activityLogs: () => activityLogs,
44
44
  authThrottle: () => authThrottle,
45
45
  deviceFingerprints: () => deviceFingerprints,
46
+ errorRefs: () => errorRefs,
46
47
  passkeys: () => passkeys,
47
48
  sessions: () => sessions,
48
49
  systemSettings: () => systemSettings,
@@ -62,7 +63,7 @@ var DEFAULT_MAINTENANCE_EXEMPT_PATHS = [
62
63
  ];
63
64
 
64
65
  // server/db/schema.ts
65
- var RoleEnum = pgCore.pgEnum("roles", ["user", "admin"]);
66
+ var RoleEnum = pgCore.pgEnum("roles", ["user", "admin", "tester"]);
66
67
  var ActivityActionEnum = pgCore.pgEnum("activity_actions", [
67
68
  "login",
68
69
  "logout",
@@ -225,6 +226,9 @@ var systemSettings = pgCore.pgTable("system_settings", {
225
226
  authEnableEmailPassword: pgCore.boolean("authEnableEmailPassword").notNull().default(true),
226
227
  authEnableOneTap: pgCore.boolean("authEnableOneTap").notNull().default(false),
227
228
  enableSessionRevocation: pgCore.boolean("enableSessionRevocation").notNull().default(true),
229
+ // Attach the error a user hit to feedback they send from it (see
230
+ // lib/feedback-route.ts). Off = only what the user typed is sent.
231
+ feedbackAttachErrors: pgCore.boolean("feedbackAttachErrors").notNull().default(true),
228
232
  updatedAt: pgCore.timestamp("updatedAt").notNull().defaultNow(),
229
233
  // Who last changed a setting. This row doesn't "belong" to that admin the
230
234
  // way sessions/activityLogs belong to their user, so deleting that admin's
@@ -233,15 +237,31 @@ var systemSettings = pgCore.pgTable("system_settings", {
233
237
  }, (table) => [
234
238
  pgCore.check("system_settings_singleton", drizzleOrm.sql`${table.id} = 'default'`)
235
239
  ]);
240
+ var errorRefs = pgCore.pgTable("error_refs", {
241
+ ref: pgCore.text("ref").primaryKey(),
242
+ message: pgCore.text("message").notNull(),
243
+ detail: pgCore.text("detail").notNull(),
244
+ createdAt: pgCore.timestamp("createdAt").notNull().defaultNow()
245
+ }, (table) => [
246
+ pgCore.index("error_refs_created_at_idx").on(table.createdAt)
247
+ ]);
236
248
  var envSchema = zod.z.object({
237
249
  NODE_ENV: zod.z.enum(["development", "production", "test"]).default("development"),
238
250
  PORT: zod.z.string().default("3000").transform(Number),
239
251
  DATABASE_URL: zod.z.string().default(""),
240
252
  RESEND_API_KEY: zod.z.string().default(""),
253
+ // Sender for every transactional email. Must be on a domain verified in
254
+ // your Resend account.
255
+ EMAIL_FROM: zod.z.string().default("Acme <onboarding@xavierkhew.xyz>"),
241
256
  // Display name for this deployment — shown as the authenticator-app label
242
257
  // (2FA issuer) and the passkey relying-party name. Consuming projects set
243
258
  // this in their own .env; defaults to the template name.
244
259
  APP_NAME: zod.z.string().default("Next.js Template"),
260
+ // Where the dashboard feedback form delivers (app/api/feedback). Set either
261
+ // or both; with neither, the Feedback button is hidden. FEEDBACK_EMAIL takes
262
+ // a comma-separated list and sends through Resend (needs RESEND_API_KEY).
263
+ FEEDBACK_DISCORD_WEBHOOK_URL: zod.z.string().default(""),
264
+ FEEDBACK_EMAIL: zod.z.string().default(""),
245
265
  // Seed-only: the live value lives in the system_settings DB row (see
246
266
  // lib/settings-queries.ts) once it's been seeded on first read, and is
247
267
  // changed from the admin System Settings page, not by editing this var.
@@ -298,6 +318,7 @@ function fallbackSettings() {
298
318
  authEnableEmailPassword: config.AUTH_ENABLE_EMAIL_PASSWORD,
299
319
  authEnableOneTap: config.AUTH_ENABLE_ONE_TAP,
300
320
  enableSessionRevocation: config.ENABLE_SESSION_REVOCATION,
321
+ feedbackAttachErrors: true,
301
322
  updatedAt: /* @__PURE__ */ new Date(0),
302
323
  updatedBy: null
303
324
  };