@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.
- package/README.md +56 -321
- package/components/dashboard/admin/adminUsersTable.tsx +36 -2
- package/components/dashboard/admin/feedbackTestForm.tsx +55 -0
- package/components/dashboard/admin/systemSettingsForm.tsx +28 -0
- package/components/dashboard/appSidebar.tsx +4 -4
- package/components/dashboard/deleteAccountCard.tsx +137 -0
- package/components/dashboard/errorFeedback.tsx +65 -0
- package/components/dashboard/feedbackDialog.tsx +160 -0
- package/components/dashboard/installAppCard.tsx +187 -0
- package/components/site/cookie-banner.tsx +57 -0
- package/components/ui/button.tsx +1 -1
- package/components/ui/file-upload.tsx +178 -0
- package/components/ui/input.tsx +1 -1
- package/components/ui/separator.tsx +1 -1
- package/components/ui/sheet.tsx +1 -1
- package/components/ui/sidebar.tsx +8 -8
- package/components/ui/skeleton.tsx +1 -1
- package/components/ui/tooltip.tsx +1 -1
- package/dist/activity/logger.js +21 -1
- 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 +21 -1
- package/dist/activity/queries.js.map +1 -1
- package/dist/activity/queries.mjs +3 -3
- package/dist/admin/queries.js +21 -1
- package/dist/admin/queries.js.map +1 -1
- package/dist/admin/queries.mjs +3 -3
- package/dist/api/feedback.d.mts +23 -0
- package/dist/api/feedback.d.ts +23 -0
- package/dist/api/feedback.js +1224 -0
- package/dist/api/feedback.js.map +1 -0
- package/dist/api/feedback.mjs +136 -0
- package/dist/api/feedback.mjs.map +1 -0
- package/dist/auth/helpers.d.mts +3 -3
- package/dist/auth/helpers.d.ts +3 -3
- package/dist/auth/helpers.js +45 -4
- package/dist/auth/helpers.js.map +1 -1
- package/dist/auth/helpers.mjs +7 -7
- package/dist/auth/helpers.mjs.map +1 -1
- package/dist/auth/index.d.mts +8 -2
- package/dist/auth/index.d.ts +8 -2
- package/dist/auth/index.js +44 -3
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/index.mjs +6 -6
- package/dist/auth-client/index.d.mts +16 -16
- package/dist/auth-client/index.d.ts +16 -16
- package/dist/{chunk-IF3JZRSZ.mjs → chunk-3MGEAGHU.mjs} +6 -5
- package/dist/chunk-3MGEAGHU.mjs.map +1 -0
- package/dist/chunk-KAEA35OC.mjs +76 -0
- package/dist/chunk-KAEA35OC.mjs.map +1 -0
- package/dist/{chunk-GTPTVNY2.mjs → chunk-TMJYAOC2.mjs} +10 -2
- package/dist/chunk-TMJYAOC2.mjs.map +1 -0
- package/dist/{chunk-OHAUKE2Q.mjs → chunk-VQ5B4MA7.mjs} +4 -4
- package/dist/{chunk-OHAUKE2Q.mjs.map → chunk-VQ5B4MA7.mjs.map} +1 -1
- package/dist/{chunk-5PYDAD4P.mjs → chunk-WZDAMCUX.mjs} +4 -4
- package/dist/{chunk-5PYDAD4P.mjs.map → chunk-WZDAMCUX.mjs.map} +1 -1
- package/dist/{chunk-V72CFFU2.mjs → chunk-XWVAJXAG.mjs} +31 -11
- package/dist/chunk-XWVAJXAG.mjs.map +1 -0
- package/dist/{chunk-4B7MJOLH.mjs → chunk-ZQCALTKB.mjs} +17 -5
- package/dist/chunk-ZQCALTKB.mjs.map +1 -0
- package/dist/config/env.d.mts +3 -0
- package/dist/config/env.d.ts +3 -0
- package/dist/config/env.js +8 -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 +21 -1
- 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 +13 -1
- package/dist/db/schema.js.map +1 -1
- package/dist/db/schema.mjs +1 -1
- package/dist/errors.d.mts +29 -0
- package/dist/errors.d.ts +29 -0
- package/dist/errors.js +365 -0
- package/dist/errors.js.map +1 -0
- package/dist/errors.mjs +7 -0
- package/dist/errors.mjs.map +1 -0
- package/dist/{schema-BghJ8N4X.d.mts → schema-BNSBWNjK.d.mts} +99 -6
- package/dist/{schema-BghJ8N4X.d.ts → schema-BNSBWNjK.d.ts} +99 -6
- package/dist/sessions/queries.js +21 -1
- package/dist/sessions/queries.js.map +1 -1
- package/dist/sessions/queries.mjs +3 -3
- package/dist/settings/queries.d.mts +2 -2
- package/dist/settings/queries.d.ts +2 -2
- package/dist/settings/queries.js +22 -1
- package/dist/settings/queries.js.map +1 -1
- package/dist/settings/queries.mjs +4 -4
- package/dist/users/queries.d.mts +3 -3
- package/dist/users/queries.d.ts +3 -3
- package/dist/users/queries.js +21 -1
- package/dist/users/queries.js.map +1 -1
- package/dist/users/queries.mjs +3 -3
- package/hooks/use-mobile.ts +19 -0
- package/lib/device-fingerprint.ts +2 -3
- package/package.json +35 -32
- package/dist/chunk-4B7MJOLH.mjs.map +0 -1
- package/dist/chunk-GTPTVNY2.mjs.map +0 -1
- package/dist/chunk-IF3JZRSZ.mjs.map +0 -1
- package/dist/chunk-V72CFFU2.mjs.map +0 -1
|
@@ -826,8 +826,8 @@ declare const authClient: better_auth_react.ReactAuthClient<{
|
|
|
826
826
|
$Infer: {
|
|
827
827
|
body: {
|
|
828
828
|
permissions: {
|
|
829
|
-
readonly user?: ("
|
|
830
|
-
readonly session?: ("
|
|
829
|
+
readonly user?: ("set-role" | "delete" | "update" | "list" | "create" | "ban" | "impersonate" | "impersonate-admins" | "set-password" | "set-email" | "get")[] | undefined;
|
|
830
|
+
readonly session?: ("delete" | "list" | "revoke")[] | undefined;
|
|
831
831
|
};
|
|
832
832
|
} & {
|
|
833
833
|
userId?: string | undefined;
|
|
@@ -916,8 +916,8 @@ declare const authClient: better_auth_react.ReactAuthClient<{
|
|
|
916
916
|
admin: {
|
|
917
917
|
checkRolePermission: <R extends "user" | "admin">(data: {
|
|
918
918
|
permissions: {
|
|
919
|
-
readonly user?: ("
|
|
920
|
-
readonly session?: ("
|
|
919
|
+
readonly user?: ("set-role" | "delete" | "update" | "list" | "create" | "ban" | "impersonate" | "impersonate-admins" | "set-password" | "set-email" | "get")[] | undefined;
|
|
920
|
+
readonly session?: ("delete" | "list" | "revoke")[] | undefined;
|
|
921
921
|
};
|
|
922
922
|
} & {
|
|
923
923
|
role: R;
|
|
@@ -2423,8 +2423,8 @@ declare const useSession: () => {
|
|
|
2423
2423
|
banned: boolean | null | undefined;
|
|
2424
2424
|
} & {
|
|
2425
2425
|
role?: string | null | undefined;
|
|
2426
|
-
banReason?: string | null | undefined;
|
|
2427
2426
|
banExpires?: Date | null | undefined;
|
|
2427
|
+
banReason?: string | null | undefined;
|
|
2428
2428
|
} & {
|
|
2429
2429
|
twoFactorEnabled: boolean | null | undefined;
|
|
2430
2430
|
} & {}>;
|
|
@@ -2450,7 +2450,7 @@ declare const useSession: () => {
|
|
|
2450
2450
|
};
|
|
2451
2451
|
declare const signIn: {
|
|
2452
2452
|
social: <FetchOptions extends better_auth.ClientFetchOption<Partial<{
|
|
2453
|
-
provider:
|
|
2453
|
+
provider: "github" | "apple" | "atlassian" | "cloudflare" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "railway" | "vercel" | "wechat" | (string & {});
|
|
2454
2454
|
callbackURL?: string | undefined;
|
|
2455
2455
|
newUserCallbackURL?: string | undefined;
|
|
2456
2456
|
errorCallbackURL?: string | undefined;
|
|
@@ -2475,7 +2475,7 @@ declare const signIn: {
|
|
|
2475
2475
|
additionalParams?: Record<string, string> | undefined;
|
|
2476
2476
|
additionalData?: Record<string, any> | undefined;
|
|
2477
2477
|
}> & Record<string, any>, Partial<Record<string, any>> & Record<string, any>, Record<string, string | undefined> | undefined>>(data_0: better_auth.Prettify<Omit<{
|
|
2478
|
-
provider:
|
|
2478
|
+
provider: "github" | "apple" | "atlassian" | "cloudflare" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "railway" | "vercel" | "wechat" | (string & {});
|
|
2479
2479
|
callbackURL?: string | undefined;
|
|
2480
2480
|
newUserCallbackURL?: string | undefined;
|
|
2481
2481
|
errorCallbackURL?: string | undefined;
|
|
@@ -2502,7 +2502,7 @@ declare const signIn: {
|
|
|
2502
2502
|
} & {
|
|
2503
2503
|
fetchOptions?: FetchOptions | undefined;
|
|
2504
2504
|
}, "provider"> & {
|
|
2505
|
-
provider:
|
|
2505
|
+
provider: "github" | "apple" | "atlassian" | "cloudflare" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "railway" | "vercel" | "wechat" | (string & {});
|
|
2506
2506
|
fetchOptions?: FetchOptions | undefined;
|
|
2507
2507
|
}>, data_1?: FetchOptions | undefined) => Promise<_better_fetch_fetch.BetterFetchResponse<{
|
|
2508
2508
|
redirect: boolean;
|
|
@@ -2533,8 +2533,8 @@ declare const signIn: {
|
|
|
2533
2533
|
banned: boolean | null | undefined;
|
|
2534
2534
|
} & {
|
|
2535
2535
|
role?: string | null | undefined;
|
|
2536
|
-
banReason?: string | null | undefined;
|
|
2537
2536
|
banExpires?: Date | null | undefined;
|
|
2537
|
+
banReason?: string | null | undefined;
|
|
2538
2538
|
} & {
|
|
2539
2539
|
twoFactorEnabled: boolean | null | undefined;
|
|
2540
2540
|
} & {}>;
|
|
@@ -2581,8 +2581,8 @@ declare const signIn: {
|
|
|
2581
2581
|
banned: boolean | null | undefined;
|
|
2582
2582
|
} & {
|
|
2583
2583
|
role?: string | null | undefined;
|
|
2584
|
-
banReason?: string | null | undefined;
|
|
2585
2584
|
banExpires?: Date | null | undefined;
|
|
2585
|
+
banReason?: string | null | undefined;
|
|
2586
2586
|
} & {
|
|
2587
2587
|
twoFactorEnabled: boolean | null | undefined;
|
|
2588
2588
|
} & {}>;
|
|
@@ -3481,8 +3481,8 @@ declare const signUp: {
|
|
|
3481
3481
|
$Infer: {
|
|
3482
3482
|
body: {
|
|
3483
3483
|
permissions: {
|
|
3484
|
-
readonly user?: ("
|
|
3485
|
-
readonly session?: ("
|
|
3484
|
+
readonly user?: ("set-role" | "delete" | "update" | "list" | "create" | "ban" | "impersonate" | "impersonate-admins" | "set-password" | "set-email" | "get")[] | undefined;
|
|
3485
|
+
readonly session?: ("delete" | "list" | "revoke")[] | undefined;
|
|
3486
3486
|
};
|
|
3487
3487
|
} & {
|
|
3488
3488
|
userId?: string | undefined;
|
|
@@ -3571,8 +3571,8 @@ declare const signUp: {
|
|
|
3571
3571
|
admin: {
|
|
3572
3572
|
checkRolePermission: <R extends "user" | "admin">(data: {
|
|
3573
3573
|
permissions: {
|
|
3574
|
-
readonly user?: ("
|
|
3575
|
-
readonly session?: ("
|
|
3574
|
+
readonly user?: ("set-role" | "delete" | "update" | "list" | "create" | "ban" | "impersonate" | "impersonate-admins" | "set-password" | "set-email" | "get")[] | undefined;
|
|
3575
|
+
readonly session?: ("delete" | "list" | "revoke")[] | undefined;
|
|
3576
3576
|
};
|
|
3577
3577
|
} & {
|
|
3578
3578
|
role: R;
|
|
@@ -5155,8 +5155,8 @@ declare const signUp: {
|
|
|
5155
5155
|
banned: boolean | null | undefined;
|
|
5156
5156
|
} & {
|
|
5157
5157
|
role?: string | null | undefined;
|
|
5158
|
-
banReason?: string | null | undefined;
|
|
5159
5158
|
banExpires?: Date | null | undefined;
|
|
5159
|
+
banReason?: string | null | undefined;
|
|
5160
5160
|
} & {
|
|
5161
5161
|
twoFactorEnabled: boolean | null | undefined;
|
|
5162
5162
|
} & {}>;
|
|
@@ -5184,8 +5184,8 @@ declare const signUp: {
|
|
|
5184
5184
|
banned: boolean | null | undefined;
|
|
5185
5185
|
} & {
|
|
5186
5186
|
role?: string | null | undefined;
|
|
5187
|
-
banReason?: string | null | undefined;
|
|
5188
5187
|
banExpires?: Date | null | undefined;
|
|
5188
|
+
banReason?: string | null | undefined;
|
|
5189
5189
|
} & {
|
|
5190
5190
|
twoFactorEnabled: boolean | null | undefined;
|
|
5191
5191
|
} & {}>;
|
|
@@ -826,8 +826,8 @@ declare const authClient: better_auth_react.ReactAuthClient<{
|
|
|
826
826
|
$Infer: {
|
|
827
827
|
body: {
|
|
828
828
|
permissions: {
|
|
829
|
-
readonly user?: ("
|
|
830
|
-
readonly session?: ("
|
|
829
|
+
readonly user?: ("set-role" | "delete" | "update" | "list" | "create" | "ban" | "impersonate" | "impersonate-admins" | "set-password" | "set-email" | "get")[] | undefined;
|
|
830
|
+
readonly session?: ("delete" | "list" | "revoke")[] | undefined;
|
|
831
831
|
};
|
|
832
832
|
} & {
|
|
833
833
|
userId?: string | undefined;
|
|
@@ -916,8 +916,8 @@ declare const authClient: better_auth_react.ReactAuthClient<{
|
|
|
916
916
|
admin: {
|
|
917
917
|
checkRolePermission: <R extends "user" | "admin">(data: {
|
|
918
918
|
permissions: {
|
|
919
|
-
readonly user?: ("
|
|
920
|
-
readonly session?: ("
|
|
919
|
+
readonly user?: ("set-role" | "delete" | "update" | "list" | "create" | "ban" | "impersonate" | "impersonate-admins" | "set-password" | "set-email" | "get")[] | undefined;
|
|
920
|
+
readonly session?: ("delete" | "list" | "revoke")[] | undefined;
|
|
921
921
|
};
|
|
922
922
|
} & {
|
|
923
923
|
role: R;
|
|
@@ -2423,8 +2423,8 @@ declare const useSession: () => {
|
|
|
2423
2423
|
banned: boolean | null | undefined;
|
|
2424
2424
|
} & {
|
|
2425
2425
|
role?: string | null | undefined;
|
|
2426
|
-
banReason?: string | null | undefined;
|
|
2427
2426
|
banExpires?: Date | null | undefined;
|
|
2427
|
+
banReason?: string | null | undefined;
|
|
2428
2428
|
} & {
|
|
2429
2429
|
twoFactorEnabled: boolean | null | undefined;
|
|
2430
2430
|
} & {}>;
|
|
@@ -2450,7 +2450,7 @@ declare const useSession: () => {
|
|
|
2450
2450
|
};
|
|
2451
2451
|
declare const signIn: {
|
|
2452
2452
|
social: <FetchOptions extends better_auth.ClientFetchOption<Partial<{
|
|
2453
|
-
provider:
|
|
2453
|
+
provider: "github" | "apple" | "atlassian" | "cloudflare" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "railway" | "vercel" | "wechat" | (string & {});
|
|
2454
2454
|
callbackURL?: string | undefined;
|
|
2455
2455
|
newUserCallbackURL?: string | undefined;
|
|
2456
2456
|
errorCallbackURL?: string | undefined;
|
|
@@ -2475,7 +2475,7 @@ declare const signIn: {
|
|
|
2475
2475
|
additionalParams?: Record<string, string> | undefined;
|
|
2476
2476
|
additionalData?: Record<string, any> | undefined;
|
|
2477
2477
|
}> & Record<string, any>, Partial<Record<string, any>> & Record<string, any>, Record<string, string | undefined> | undefined>>(data_0: better_auth.Prettify<Omit<{
|
|
2478
|
-
provider:
|
|
2478
|
+
provider: "github" | "apple" | "atlassian" | "cloudflare" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "railway" | "vercel" | "wechat" | (string & {});
|
|
2479
2479
|
callbackURL?: string | undefined;
|
|
2480
2480
|
newUserCallbackURL?: string | undefined;
|
|
2481
2481
|
errorCallbackURL?: string | undefined;
|
|
@@ -2502,7 +2502,7 @@ declare const signIn: {
|
|
|
2502
2502
|
} & {
|
|
2503
2503
|
fetchOptions?: FetchOptions | undefined;
|
|
2504
2504
|
}, "provider"> & {
|
|
2505
|
-
provider:
|
|
2505
|
+
provider: "github" | "apple" | "atlassian" | "cloudflare" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "railway" | "vercel" | "wechat" | (string & {});
|
|
2506
2506
|
fetchOptions?: FetchOptions | undefined;
|
|
2507
2507
|
}>, data_1?: FetchOptions | undefined) => Promise<_better_fetch_fetch.BetterFetchResponse<{
|
|
2508
2508
|
redirect: boolean;
|
|
@@ -2533,8 +2533,8 @@ declare const signIn: {
|
|
|
2533
2533
|
banned: boolean | null | undefined;
|
|
2534
2534
|
} & {
|
|
2535
2535
|
role?: string | null | undefined;
|
|
2536
|
-
banReason?: string | null | undefined;
|
|
2537
2536
|
banExpires?: Date | null | undefined;
|
|
2537
|
+
banReason?: string | null | undefined;
|
|
2538
2538
|
} & {
|
|
2539
2539
|
twoFactorEnabled: boolean | null | undefined;
|
|
2540
2540
|
} & {}>;
|
|
@@ -2581,8 +2581,8 @@ declare const signIn: {
|
|
|
2581
2581
|
banned: boolean | null | undefined;
|
|
2582
2582
|
} & {
|
|
2583
2583
|
role?: string | null | undefined;
|
|
2584
|
-
banReason?: string | null | undefined;
|
|
2585
2584
|
banExpires?: Date | null | undefined;
|
|
2585
|
+
banReason?: string | null | undefined;
|
|
2586
2586
|
} & {
|
|
2587
2587
|
twoFactorEnabled: boolean | null | undefined;
|
|
2588
2588
|
} & {}>;
|
|
@@ -3481,8 +3481,8 @@ declare const signUp: {
|
|
|
3481
3481
|
$Infer: {
|
|
3482
3482
|
body: {
|
|
3483
3483
|
permissions: {
|
|
3484
|
-
readonly user?: ("
|
|
3485
|
-
readonly session?: ("
|
|
3484
|
+
readonly user?: ("set-role" | "delete" | "update" | "list" | "create" | "ban" | "impersonate" | "impersonate-admins" | "set-password" | "set-email" | "get")[] | undefined;
|
|
3485
|
+
readonly session?: ("delete" | "list" | "revoke")[] | undefined;
|
|
3486
3486
|
};
|
|
3487
3487
|
} & {
|
|
3488
3488
|
userId?: string | undefined;
|
|
@@ -3571,8 +3571,8 @@ declare const signUp: {
|
|
|
3571
3571
|
admin: {
|
|
3572
3572
|
checkRolePermission: <R extends "user" | "admin">(data: {
|
|
3573
3573
|
permissions: {
|
|
3574
|
-
readonly user?: ("
|
|
3575
|
-
readonly session?: ("
|
|
3574
|
+
readonly user?: ("set-role" | "delete" | "update" | "list" | "create" | "ban" | "impersonate" | "impersonate-admins" | "set-password" | "set-email" | "get")[] | undefined;
|
|
3575
|
+
readonly session?: ("delete" | "list" | "revoke")[] | undefined;
|
|
3576
3576
|
};
|
|
3577
3577
|
} & {
|
|
3578
3578
|
role: R;
|
|
@@ -5155,8 +5155,8 @@ declare const signUp: {
|
|
|
5155
5155
|
banned: boolean | null | undefined;
|
|
5156
5156
|
} & {
|
|
5157
5157
|
role?: string | null | undefined;
|
|
5158
|
-
banReason?: string | null | undefined;
|
|
5159
5158
|
banExpires?: Date | null | undefined;
|
|
5159
|
+
banReason?: string | null | undefined;
|
|
5160
5160
|
} & {
|
|
5161
5161
|
twoFactorEnabled: boolean | null | undefined;
|
|
5162
5162
|
} & {}>;
|
|
@@ -5184,8 +5184,8 @@ declare const signUp: {
|
|
|
5184
5184
|
banned: boolean | null | undefined;
|
|
5185
5185
|
} & {
|
|
5186
5186
|
role?: string | null | undefined;
|
|
5187
|
-
banReason?: string | null | undefined;
|
|
5188
5187
|
banExpires?: Date | null | undefined;
|
|
5188
|
+
banReason?: string | null | undefined;
|
|
5189
5189
|
} & {
|
|
5190
5190
|
twoFactorEnabled: boolean | null | undefined;
|
|
5191
5191
|
} & {}>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { db } from './chunk-
|
|
2
|
-
import { systemSettings, DEFAULT_MAINTENANCE_EXEMPT_PATHS } from './chunk-
|
|
3
|
-
import { config } from './chunk-
|
|
1
|
+
import { db } from './chunk-WZDAMCUX.mjs';
|
|
2
|
+
import { systemSettings, DEFAULT_MAINTENANCE_EXEMPT_PATHS } from './chunk-ZQCALTKB.mjs';
|
|
3
|
+
import { config } from './chunk-TMJYAOC2.mjs';
|
|
4
4
|
import { __spreadProps, __spreadValues } from './chunk-3465SI5N.mjs';
|
|
5
5
|
import 'server-only';
|
|
6
6
|
import { eq } from 'drizzle-orm';
|
|
@@ -18,6 +18,7 @@ function fallbackSettings() {
|
|
|
18
18
|
authEnableEmailPassword: config.AUTH_ENABLE_EMAIL_PASSWORD,
|
|
19
19
|
authEnableOneTap: config.AUTH_ENABLE_ONE_TAP,
|
|
20
20
|
enableSessionRevocation: config.ENABLE_SESSION_REVOCATION,
|
|
21
|
+
feedbackAttachErrors: true,
|
|
21
22
|
updatedAt: /* @__PURE__ */ new Date(0),
|
|
22
23
|
updatedBy: null
|
|
23
24
|
};
|
|
@@ -76,5 +77,5 @@ function getConfiguredAuthFlags() {
|
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
export { getConfiguredAuthFlags, getEffectiveAuthFlags, getSystemSettings, invalidateSystemSettingsCache, updateSystemSettings };
|
|
79
|
-
//# sourceMappingURL=chunk-
|
|
80
|
-
//# sourceMappingURL=chunk-
|
|
80
|
+
//# sourceMappingURL=chunk-3MGEAGHU.mjs.map
|
|
81
|
+
//# sourceMappingURL=chunk-3MGEAGHU.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../lib/settings-queries.ts"],"names":[],"mappings":"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","file":"chunk-3MGEAGHU.mjs","sourcesContent":["import \"server-only\"\nimport { db } from \"../server/db\"\nimport { systemSettings } from \"../server/db/schema\"\nimport { config } from \"../config/env\"\nimport { eq } from \"drizzle-orm\"\nimport { DEFAULT_MAINTENANCE_EXEMPT_PATHS } from \"./maintenance\"\n\nconst SETTINGS_ROW_ID = \"default\"\n// Short TTL: cheap reads (no DB round trip on every request), while an\n// admin's change is guaranteed live within this window even for a reader\n// that isn't the one who just saved (invalidateSystemSettingsCache() makes\n// it instant for that request's own process).\nconst CACHE_TTL_MS = 10_000\n\nexport type SystemSettings = typeof systemSettings.$inferSelect\n\nlet cached: { value: SystemSettings; expiresAt: number } | null = null\n\n// Fail-open shape if the DB is unreachable: auth flags fall back to their\n// config/env.ts defaults (unchanged behavior), maintenance mode is always\n// off — a DB hiccup must never lock out the whole site, including admins.\nfunction fallbackSettings(): SystemSettings {\n return {\n id: SETTINGS_ROW_ID,\n maintenanceMode: false,\n maintenanceMessage: null,\n maintenanceExemptPaths: DEFAULT_MAINTENANCE_EXEMPT_PATHS,\n authEnableGoogle: config.AUTH_ENABLE_GOOGLE,\n authEnableEmailPassword: config.AUTH_ENABLE_EMAIL_PASSWORD,\n authEnableOneTap: config.AUTH_ENABLE_ONE_TAP,\n enableSessionRevocation: config.ENABLE_SESSION_REVOCATION,\n feedbackAttachErrors: true,\n updatedAt: new Date(0),\n updatedBy: null,\n }\n}\n\nasync function loadOrSeed(): Promise<SystemSettings> {\n const existing = await db\n .select()\n .from(systemSettings)\n .where(eq(systemSettings.id, SETTINGS_ROW_ID))\n .limit(1)\n if (existing[0]) return existing[0]\n\n // Lazy-seed on first read, from the *current* env config — not the\n // schema's hardcoded column defaults — so turning this feature on never\n // silently flips an already-deployed flag (e.g. a prod deploy that\n // already set AUTH_ENABLE_GOOGLE=false).\n const seeded = await db\n .insert(systemSettings)\n .values({\n id: SETTINGS_ROW_ID,\n maintenanceMode: false,\n authEnableGoogle: config.AUTH_ENABLE_GOOGLE,\n authEnableEmailPassword: config.AUTH_ENABLE_EMAIL_PASSWORD,\n authEnableOneTap: config.AUTH_ENABLE_ONE_TAP,\n enableSessionRevocation: config.ENABLE_SESSION_REVOCATION,\n })\n .onConflictDoNothing()\n .returning()\n\n if (seeded[0]) return seeded[0]\n\n // Lost the seed race to a concurrent first-reader.\n const retry = await db\n .select()\n .from(systemSettings)\n .where(eq(systemSettings.id, SETTINGS_ROW_ID))\n .limit(1)\n return retry[0] ?? fallbackSettings()\n}\n\nexport async function getSystemSettings(): Promise<SystemSettings> {\n const now = Date.now()\n if (cached && cached.expiresAt > now) return cached.value\n\n try {\n const value = await loadOrSeed()\n cached = { value, expiresAt: now + CACHE_TTL_MS }\n return value\n } catch (error) {\n console.error(\"Failed to load system settings, failing open:\", error)\n return fallbackSettings() // not cached — retry next request\n }\n}\n\nexport function invalidateSystemSettingsCache() {\n cached = null\n}\n\nexport type SystemSettingsPatch = Partial<Pick<SystemSettings,\n | 'maintenanceMode' | 'maintenanceMessage' | 'maintenanceExemptPaths'\n | 'authEnableGoogle' | 'authEnableEmailPassword' | 'authEnableOneTap'\n | 'enableSessionRevocation' | 'feedbackAttachErrors'\n>>\n\nexport async function updateSystemSettings(\n patch: SystemSettingsPatch,\n updatedBy: string\n): Promise<SystemSettings> {\n await loadOrSeed() // ensure the row exists even if nobody's read it yet\n\n const [updated] = await db\n .update(systemSettings)\n .set({ ...patch, updatedAt: new Date(), updatedBy })\n .where(eq(systemSettings.id, SETTINGS_ROW_ID))\n .returning()\n\n invalidateSystemSettingsCache()\n return updated\n}\n\n// Effective auth-method visibility = deploy-time \"configured\" (env, decides\n// whether the provider is even registered with better-auth — see\n// server/auth.ts's createAuth()) AND runtime \"offered\" (this DB flag).\nexport async function getEffectiveAuthFlags() {\n const settings = await getSystemSettings()\n return {\n google: config.AUTH_ENABLE_GOOGLE && settings.authEnableGoogle,\n emailPassword: config.AUTH_ENABLE_EMAIL_PASSWORD && settings.authEnableEmailPassword,\n oneTap: config.AUTH_ENABLE_ONE_TAP && settings.authEnableOneTap,\n }\n}\n\n// The env-only half of the AND above. The System Settings page needs this\n// to explain *why* a toggle it controls isn't taking effect — flipping the\n// DB flag on can't do anything if the env var for that method is off, so\n// the UI should say so instead of looking like a silent no-op.\nexport function getConfiguredAuthFlags() {\n return {\n google: config.AUTH_ENABLE_GOOGLE,\n emailPassword: config.AUTH_ENABLE_EMAIL_PASSWORD,\n oneTap: config.AUTH_ENABLE_ONE_TAP,\n }\n}\n"]}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { db } from './chunk-WZDAMCUX.mjs';
|
|
2
|
+
import { errorRefs } from './chunk-ZQCALTKB.mjs';
|
|
3
|
+
import 'server-only';
|
|
4
|
+
import { randomBytes } from 'crypto';
|
|
5
|
+
import { after } from 'next/server';
|
|
6
|
+
import { eq, lt } from 'drizzle-orm';
|
|
7
|
+
|
|
8
|
+
var REF_ALPHABET = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
|
|
9
|
+
var REF_PATTERN = /\(ref: ([2-9A-HJ-NP-Z]{6})\)/;
|
|
10
|
+
var DETAIL_MAX_LENGTH = 8e3;
|
|
11
|
+
var RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
12
|
+
function describeError(error) {
|
|
13
|
+
if (error instanceof Error) return error.stack || `${error.name}: ${error.message}`;
|
|
14
|
+
try {
|
|
15
|
+
return JSON.stringify(error, null, 2);
|
|
16
|
+
} catch (e) {
|
|
17
|
+
return String(error);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function storeDetail(ref, message, error) {
|
|
21
|
+
const save = async () => {
|
|
22
|
+
try {
|
|
23
|
+
await db.insert(errorRefs).values({
|
|
24
|
+
ref,
|
|
25
|
+
message,
|
|
26
|
+
detail: describeError(error).slice(0, DETAIL_MAX_LENGTH)
|
|
27
|
+
});
|
|
28
|
+
await db.delete(errorRefs).where(lt(errorRefs.createdAt, new Date(Date.now() - RETENTION_MS)));
|
|
29
|
+
} catch (storeError) {
|
|
30
|
+
console.error(`[error ref ${ref}] could not store error detail`, storeError);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
try {
|
|
34
|
+
after(save);
|
|
35
|
+
} catch (e) {
|
|
36
|
+
void save();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async function lookupErrorDetail(text) {
|
|
40
|
+
var _a, _b;
|
|
41
|
+
const ref = (_a = text.match(REF_PATTERN)) == null ? void 0 : _a[1];
|
|
42
|
+
if (!ref) return null;
|
|
43
|
+
const [row] = await db.select({ detail: errorRefs.detail }).from(errorRefs).where(eq(errorRefs.ref, ref)).limit(1);
|
|
44
|
+
return (_b = row == null ? void 0 : row.detail) != null ? _b : null;
|
|
45
|
+
}
|
|
46
|
+
function unexpectedErrorMessage(error, message = "Something went wrong. Please try again.") {
|
|
47
|
+
const ref = Array.from(randomBytes(6), (b) => REF_ALPHABET[b % REF_ALPHABET.length]).join("");
|
|
48
|
+
console.error(`[error ref ${ref}] ${message}`, error);
|
|
49
|
+
storeDetail(ref, message, error);
|
|
50
|
+
return `${message} (ref: ${ref})`;
|
|
51
|
+
}
|
|
52
|
+
var ActionError = class extends Error {
|
|
53
|
+
};
|
|
54
|
+
function isFrameworkControlFlowError(error) {
|
|
55
|
+
const digest = error == null ? void 0 : error.digest;
|
|
56
|
+
return typeof digest === "string" && (digest.startsWith("NEXT_REDIRECT") || digest.startsWith("NEXT_HTTP_ERROR_FALLBACK"));
|
|
57
|
+
}
|
|
58
|
+
function withActionErrors(action) {
|
|
59
|
+
return async (...args) => {
|
|
60
|
+
try {
|
|
61
|
+
return { ok: true, data: await action(...args) };
|
|
62
|
+
} catch (error) {
|
|
63
|
+
if (error instanceof ActionError) {
|
|
64
|
+
return { ok: false, message: error.message };
|
|
65
|
+
}
|
|
66
|
+
if (isFrameworkControlFlowError(error)) {
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
return { ok: false, message: unexpectedErrorMessage(error) };
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export { ActionError, lookupErrorDetail, unexpectedErrorMessage, withActionErrors };
|
|
75
|
+
//# sourceMappingURL=chunk-KAEA35OC.mjs.map
|
|
76
|
+
//# sourceMappingURL=chunk-KAEA35OC.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../lib/errors.ts"],"names":[],"mappings":"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","file":"chunk-KAEA35OC.mjs","sourcesContent":["import \"server-only\"\nimport { randomBytes } from \"node:crypto\"\nimport { after } from \"next/server\"\nimport { eq, lt } from \"drizzle-orm\"\nimport { db } from \"../server/db\"\nimport { errorRefs } from \"../server/db/schema\"\n\n// No 0/O/1/I so a user can read a ref back without mix-ups.\nconst REF_ALPHABET = \"23456789ABCDEFGHJKLMNPQRSTUVWXYZ\"\nconst REF_PATTERN = /\\(ref: ([2-9A-HJ-NP-Z]{6})\\)/\nconst DETAIL_MAX_LENGTH = 8000\nconst RETENTION_MS = 30 * 24 * 60 * 60 * 1000\n\nfunction describeError(error: unknown): string {\n if (error instanceof Error) return error.stack || `${error.name}: ${error.message}`\n try {\n return JSON.stringify(error, null, 2)\n } catch {\n return String(error)\n }\n}\n\n// Saves the detail so a later feedback report can carry it. Runs after the\n// response when inside a request (after()), and never fails the caller.\nfunction storeDetail(ref: string, message: string, error: unknown) {\n const save = async () => {\n try {\n await db.insert(errorRefs).values({\n ref,\n message,\n detail: describeError(error).slice(0, DETAIL_MAX_LENGTH),\n })\n // ponytail: prune on insert; a scheduled cleanup if error volume ever gets high.\n await db.delete(errorRefs).where(lt(errorRefs.createdAt, new Date(Date.now() - RETENTION_MS)))\n } catch (storeError) {\n console.error(`[error ref ${ref}] could not store error detail`, storeError)\n }\n }\n try {\n after(save)\n } catch {\n void save() // outside a request scope (e.g. a script)\n }\n}\n\n/** The stored technical detail for the ref inside a user-facing error message, if any. */\nexport async function lookupErrorDetail(text: string): Promise<string | null> {\n const ref = text.match(REF_PATTERN)?.[1]\n if (!ref) return null\n const [row] = await db\n .select({ detail: errorRefs.detail })\n .from(errorRefs)\n .where(eq(errorRefs.ref, ref))\n .limit(1)\n return row?.detail ?? null\n}\n\n/**\n * Logs an unexpected error under a short reference and returns the message to\n * show instead, e.g. \"Failed to update role (ref: K7Q2PX)\". The user, and any\n * feedback report they send, only ever get the ref. The error itself goes to\n * the server log (\"error ref K7Q2PX\") and the error_refs table, from which the\n * feedback route attaches it to reports sent to Discord/email.\n */\nexport function unexpectedErrorMessage(\n error: unknown,\n message = \"Something went wrong. Please try again.\"\n): string {\n const ref = Array.from(randomBytes(6), (b) => REF_ALPHABET[b % REF_ALPHABET.length]).join(\"\")\n console.error(`[error ref ${ref}] ${message}`, error)\n storeDetail(ref, message, error)\n return `${message} (ref: ${ref})`\n}\n\n/**\n * Throw this for messages that are safe to show to the end user (validation,\n * permission, and state-conflict errors). Anything else thrown inside a\n * `withActionErrors`-wrapped action is logged server-side and replaced with a\n * generic message carrying an error ref.\n */\nexport class ActionError extends Error {}\n\nexport type ActionResult<T> =\n | { ok: true; data: T }\n | { ok: false; message: string }\n\nfunction isFrameworkControlFlowError(error: unknown): boolean {\n const digest = (error as { digest?: unknown } | null)?.digest\n return (\n typeof digest === \"string\" &&\n (digest.startsWith(\"NEXT_REDIRECT\") || digest.startsWith(\"NEXT_HTTP_ERROR_FALLBACK\"))\n )\n}\n\n/** Wraps a server action so it returns an ActionResult instead of throwing. */\nexport function withActionErrors<Args extends unknown[], T>(\n action: (...args: Args) => Promise<T>\n): (...args: Args) => Promise<ActionResult<T>> {\n return async (...args: Args): Promise<ActionResult<T>> => {\n try {\n return { ok: true, data: await action(...args) }\n } catch (error) {\n if (error instanceof ActionError) {\n return { ok: false, message: error.message }\n }\n if (isFrameworkControlFlowError(error)) {\n throw error\n }\n // Returned, not thrown: Next.js replaces thrown server-action messages\n // in production, which would drop the ref.\n return { ok: false, message: unexpectedErrorMessage(error) }\n }\n }\n}\n"]}
|
|
@@ -7,10 +7,18 @@ var envSchema = z.object({
|
|
|
7
7
|
PORT: z.string().default("3000").transform(Number),
|
|
8
8
|
DATABASE_URL: z.string().default(""),
|
|
9
9
|
RESEND_API_KEY: z.string().default(""),
|
|
10
|
+
// Sender for every transactional email. Must be on a domain verified in
|
|
11
|
+
// your Resend account.
|
|
12
|
+
EMAIL_FROM: z.string().default("Acme <onboarding@xavierkhew.xyz>"),
|
|
10
13
|
// Display name for this deployment — shown as the authenticator-app label
|
|
11
14
|
// (2FA issuer) and the passkey relying-party name. Consuming projects set
|
|
12
15
|
// this in their own .env; defaults to the template name.
|
|
13
16
|
APP_NAME: z.string().default("Next.js Template"),
|
|
17
|
+
// Where the dashboard feedback form delivers (app/api/feedback). Set either
|
|
18
|
+
// or both; with neither, the Feedback button is hidden. FEEDBACK_EMAIL takes
|
|
19
|
+
// a comma-separated list and sends through Resend (needs RESEND_API_KEY).
|
|
20
|
+
FEEDBACK_DISCORD_WEBHOOK_URL: z.string().default(""),
|
|
21
|
+
FEEDBACK_EMAIL: z.string().default(""),
|
|
14
22
|
// Seed-only: the live value lives in the system_settings DB row (see
|
|
15
23
|
// lib/settings-queries.ts) once it's been seeded on first read, and is
|
|
16
24
|
// changed from the admin System Settings page, not by editing this var.
|
|
@@ -36,5 +44,5 @@ if (!results.success) {
|
|
|
36
44
|
var config = results.data;
|
|
37
45
|
|
|
38
46
|
export { config };
|
|
39
|
-
//# sourceMappingURL=chunk-
|
|
40
|
-
//# sourceMappingURL=chunk-
|
|
47
|
+
//# sourceMappingURL=chunk-TMJYAOC2.mjs.map
|
|
48
|
+
//# sourceMappingURL=chunk-TMJYAOC2.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../config/env-schema.ts","../config/env.ts"],"names":[],"mappings":";;;;AAMO,IAAM,SAAA,GAAY,EAAE,MAAA,CAAO;AAAA,EAChC,QAAA,EAAU,CAAA,CAAE,IAAA,CAAK,CAAC,aAAA,EAAe,cAAc,MAAM,CAAC,CAAA,CAAE,OAAA,CAAQ,aAAa,CAAA;AAAA,EAC7E,IAAA,EAAM,EAAE,MAAA,EAAO,CAAE,QAAQ,MAAM,CAAA,CAAE,UAAU,MAAM,CAAA;AAAA,EACjD,YAAA,EAAc,CAAA,CAAE,MAAA,EAAO,CAAE,QAAQ,EAAE,CAAA;AAAA,EACnC,cAAA,EAAgB,CAAA,CAAE,MAAA,EAAO,CAAE,QAAQ,EAAE,CAAA;AAAA;AAAA;AAAA,EAGrC,UAAA,EAAY,CAAA,CAAE,MAAA,EAAO,CAAE,QAAQ,kCAAkC,CAAA;AAAA;AAAA;AAAA;AAAA,EAIjE,QAAA,EAAU,CAAA,CAAE,MAAA,EAAO,CAAE,QAAQ,kBAAkB,CAAA;AAAA;AAAA;AAAA;AAAA,EAI/C,4BAAA,EAA8B,CAAA,CAAE,MAAA,EAAO,CAAE,QAAQ,EAAE,CAAA;AAAA,EACnD,cAAA,EAAgB,CAAA,CAAE,MAAA,EAAO,CAAE,QAAQ,EAAE,CAAA;AAAA;AAAA;AAAA;AAAA,EAIrC,yBAAA,EAA2B,CAAA,CAAE,MAAA,EAAO,CAAE,OAAA,CAAQ,MAAM,CAAA,CAAE,SAAA,CAAU,CAAA,GAAA,KAAO,GAAA,KAAQ,MAAM,CAAA;AAAA,EACrF,kBAAA,EAAoB,CAAA,CAAE,MAAA,EAAO,CAAE,OAAA,CAAQ,MAAM,CAAA,CAAE,SAAA,CAAU,CAAA,GAAA,KAAO,GAAA,KAAQ,MAAM,CAAA;AAAA,EAC9E,0BAAA,EAA4B,CAAA,CAAE,MAAA,EAAO,CAAE,OAAA,CAAQ,MAAM,CAAA,CAAE,SAAA,CAAU,CAAA,GAAA,KAAO,GAAA,KAAQ,MAAM,CAAA;AAAA,EACtF,mBAAA,EAAqB,CAAA,CAAE,MAAA,EAAO,CAAE,OAAA,CAAQ,OAAO,CAAA,CAAE,SAAA,CAAU,CAAA,GAAA,KAAO,GAAA,KAAQ,MAAM,CAAA;AAAA,EAChF,SAAA,EAAW,EAAE,IAAA,CAAK,CAAC,MAAM,MAAM,CAAC,CAAA,CAAE,OAAA,CAAQ,IAAI,CAAA;AAAA;AAAA;AAAA,EAG9C,YAAA,EAAc,CAAA,CAAE,MAAA,EAAO,CAAE,OAAA,CAAQ,OAAO,CAAA,CAAE,SAAA,CAAU,CAAA,GAAA,KAAO,GAAA,KAAQ,MAAM;AAC3E,CAAC,CAAA;;;AC/BD,IAAM,OAAA,GAAU,SAAA,CAAU,SAAA,CAAU,OAAA,CAAQ,GAAG,CAAA;AAE/C,IAAI,OAAA,CAAQ,OAAA,IAAY,OAAA,CAAQ,IAAA,CAAK,aAAa,aAAA,EAAgB;AAChE,EAAA,OAAA,CAAQ,IAAI,+BAAA,EAAiC,MAAA,CAAO,IAAA,CAAK,OAAA,CAAQ,IAAI,CAAC,CAAA;AACxE;AAEA,IAAI,CAAC,QAAQ,OAAA,EAAS;AACpB,EAAA,OAAA,CAAQ,KAAA,CAAM,gCAAA,EAAkC,OAAA,CAAQ,KAAA,CAAM,QAAQ,CAAA;AACtE,EAAA,MAAM,IAAI,MAAM,+BAA+B,CAAA;AACjD;AAEO,IAAM,SAAS,OAAA,CAAQ","file":"chunk-TMJYAOC2.mjs","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 // 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"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { db } from './chunk-
|
|
2
|
-
import { activityLogs } from './chunk-
|
|
1
|
+
import { db } from './chunk-WZDAMCUX.mjs';
|
|
2
|
+
import { activityLogs } from './chunk-ZQCALTKB.mjs';
|
|
3
3
|
import 'server-only';
|
|
4
4
|
|
|
5
5
|
async function logActivity({
|
|
@@ -37,5 +37,5 @@ async function logActivity({
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export { logActivity };
|
|
40
|
-
//# sourceMappingURL=chunk-
|
|
41
|
-
//# sourceMappingURL=chunk-
|
|
40
|
+
//# sourceMappingURL=chunk-VQ5B4MA7.mjs.map
|
|
41
|
+
//# sourceMappingURL=chunk-VQ5B4MA7.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../lib/activity-logger.ts"],"names":[],"mappings":";;;;AAsCA,eAAsB,WAAA,CAAY;AAAA,EAChC,MAAA;AAAA,EACA,MAAA;AAAA,EACA,WAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,WAAA;AAAA,EACA,EAAA;AAAA,EACA,OAAA;AAAA,EACA,UAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,EAAsB;AACpB,EAAA,IAAI;AACF,IAAA,MAAM,EAAA,CAAG,MAAA,CAAO,YAAY,CAAA,CAAE,MAAA,CAAO;AAAA,MACnC,MAAA;AAAA,MACA,MAAA;AAAA,MACA,WAAA;AAAA,MACA,WAAW,SAAA,IAAa,IAAA;AAAA,MACxB,WAAW,SAAA,IAAa,IAAA;AAAA,MACxB,QAAA,EAAU,QAAA,GAAW,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAA,GAAI,IAAA;AAAA,MAChD,aAAa,WAAA,IAAe,IAAA;AAAA,MAC5B,IAAI,EAAA,IAAM,IAAA;AAAA,MACV,SAAS,OAAA,IAAW,IAAA;AAAA,MACpB,YAAY,UAAA,IAAc,IAAA;AAAA,MAC1B,SAAS,OAAA,IAAW,IAAA;AAAA,MACpB,MAAM,IAAA,IAAQ;AAAA,KACf,CAAA;AAAA,EACH,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,2BAA2B,KAAK,CAAA;AAAA,EAEhD;AACF","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../lib/activity-logger.ts"],"names":[],"mappings":";;;;AAsCA,eAAsB,WAAA,CAAY;AAAA,EAChC,MAAA;AAAA,EACA,MAAA;AAAA,EACA,WAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,WAAA;AAAA,EACA,EAAA;AAAA,EACA,OAAA;AAAA,EACA,UAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,EAAsB;AACpB,EAAA,IAAI;AACF,IAAA,MAAM,EAAA,CAAG,MAAA,CAAO,YAAY,CAAA,CAAE,MAAA,CAAO;AAAA,MACnC,MAAA;AAAA,MACA,MAAA;AAAA,MACA,WAAA;AAAA,MACA,WAAW,SAAA,IAAa,IAAA;AAAA,MACxB,WAAW,SAAA,IAAa,IAAA;AAAA,MACxB,QAAA,EAAU,QAAA,GAAW,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAA,GAAI,IAAA;AAAA,MAChD,aAAa,WAAA,IAAe,IAAA;AAAA,MAC5B,IAAI,EAAA,IAAM,IAAA;AAAA,MACV,SAAS,OAAA,IAAW,IAAA;AAAA,MACpB,YAAY,UAAA,IAAc,IAAA;AAAA,MAC1B,SAAS,OAAA,IAAW,IAAA;AAAA,MACpB,MAAM,IAAA,IAAQ;AAAA,KACf,CAAA;AAAA,EACH,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,2BAA2B,KAAK,CAAA;AAAA,EAEhD;AACF","file":"chunk-VQ5B4MA7.mjs","sourcesContent":["import \"server-only\"\nimport { db } from \"../server/db\"\nimport { activityLogs } from \"../server/db/schema\"\n\nexport type ActivityAction =\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\ninterface LogActivityParams {\n userId: string\n action: ActivityAction\n description: string\n ipAddress?: string | null\n userAgent?: string | null\n metadata?: Record<string, any>\n // Populated on 'login' events only — see server/auth.ts's session.create hook.\n referrerUrl?: string | null\n os?: string | null\n browser?: string | null\n deviceType?: string | null\n country?: string | null\n city?: string | null\n}\n\nexport async function logActivity({\n userId,\n action,\n description,\n ipAddress,\n userAgent,\n metadata,\n referrerUrl,\n os,\n browser,\n deviceType,\n country,\n city,\n}: LogActivityParams) {\n try {\n await db.insert(activityLogs).values({\n userId,\n action,\n description,\n ipAddress: ipAddress || null,\n userAgent: userAgent || null,\n metadata: metadata ? JSON.stringify(metadata) : null,\n referrerUrl: referrerUrl || null,\n os: os || null,\n browser: browser || null,\n deviceType: deviceType || null,\n country: country || null,\n city: city || null,\n })\n } catch (error) {\n console.error('Failed to log activity:', error)\n // Don't throw - activity logging should not break the app\n }\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { schema_exports } from './chunk-
|
|
2
|
-
import { config } from './chunk-
|
|
1
|
+
import { schema_exports } from './chunk-ZQCALTKB.mjs';
|
|
2
|
+
import { config } from './chunk-TMJYAOC2.mjs';
|
|
3
3
|
import 'server-only';
|
|
4
4
|
import { neon } from '@neondatabase/serverless';
|
|
5
5
|
import { drizzle as drizzle$1 } from 'drizzle-orm/neon-http';
|
|
@@ -26,5 +26,5 @@ if (config.DB_DRIVER === "pg") {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export { db };
|
|
29
|
-
//# sourceMappingURL=chunk-
|
|
30
|
-
//# sourceMappingURL=chunk-
|
|
29
|
+
//# sourceMappingURL=chunk-WZDAMCUX.mjs.map
|
|
30
|
+
//# sourceMappingURL=chunk-WZDAMCUX.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../server/db/index.ts"],"names":["drizzlePg","drizzle"],"mappings":";;;;;;;;AAoBA,IAAI;AAGJ,IAAI,MAAA,CAAO,cAAc,IAAA,EAAM;AAC7B,EAAA,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK;AAAA,IACpB,kBAAkB,MAAA,CAAO,YAAA;AAAA,IACzB,KAAK,MAAA,CAAO,YAAA,GAAe,EAAE,kBAAA,EAAoB,OAAM,GAAI;AAAA,GAC5D,CAAA;AACD,EAAA,EAAA,GAAKA,QAAU,IAAA,EAAM;AAAA,IACnB,MAAA,EAAA,cAAA;AAAA,IACA,MAAA,EAAQ;AAAA,GACT,CAAA;AAED,EAAA,OAAA,CAAQ,IAAI,wCAAiC,CAAA;AAE/C,CAAA,MAAA,IAAW,MAAA,CAAO,cAAc,MAAA,EAAQ;AACtC,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,MAAA,CAAO,YAAa,CAAA;AACrC,EAAA,EAAA,GAAKC,UAAQ,GAAA,EAAK,EAAE,MAAA,EAAA,cAAA,EAAQ,MAAA,EAAQ,MAAM,CAAA;AAE1C,EAAA,OAAA,CAAQ,IAAI,oCAA6B,CAAA;AAE3C,CAAA,MAAO;AACL,EAAA,OAAA,CAAQ,GAAA,CAAI,yDAAA,EAA2D,MAAA,CAAO,SAAS,CAAA;AACzF","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../server/db/index.ts"],"names":["drizzlePg","drizzle"],"mappings":";;;;;;;;AAoBA,IAAI;AAGJ,IAAI,MAAA,CAAO,cAAc,IAAA,EAAM;AAC7B,EAAA,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK;AAAA,IACpB,kBAAkB,MAAA,CAAO,YAAA;AAAA,IACzB,KAAK,MAAA,CAAO,YAAA,GAAe,EAAE,kBAAA,EAAoB,OAAM,GAAI;AAAA,GAC5D,CAAA;AACD,EAAA,EAAA,GAAKA,QAAU,IAAA,EAAM;AAAA,IACnB,MAAA,EAAA,cAAA;AAAA,IACA,MAAA,EAAQ;AAAA,GACT,CAAA;AAED,EAAA,OAAA,CAAQ,IAAI,wCAAiC,CAAA;AAE/C,CAAA,MAAA,IAAW,MAAA,CAAO,cAAc,MAAA,EAAQ;AACtC,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,MAAA,CAAO,YAAa,CAAA;AACrC,EAAA,EAAA,GAAKC,UAAQ,GAAA,EAAK,EAAE,MAAA,EAAA,cAAA,EAAQ,MAAA,EAAQ,MAAM,CAAA;AAE1C,EAAA,OAAA,CAAQ,IAAI,oCAA6B,CAAA;AAE3C,CAAA,MAAO;AACL,EAAA,OAAA,CAAQ,GAAA,CAAI,yDAAA,EAA2D,MAAA,CAAO,SAAS,CAAA;AACzF","file":"chunk-WZDAMCUX.mjs","sourcesContent":["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 }"]}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { logActivity } from './chunk-
|
|
1
|
+
import { logActivity } from './chunk-VQ5B4MA7.mjs';
|
|
2
2
|
import { getClientIp, parseUserAgent, lookupGeoLocation, formatLocation, formatDeviceInfo, WINDOW_MS, isOverLimit, MAX_IP } from './chunk-N6ECRCHY.mjs';
|
|
3
|
-
import { getEffectiveAuthFlags } from './chunk-
|
|
4
|
-
import { db } from './chunk-
|
|
5
|
-
import { users, sessions, passkeys, twoFactors, verifications, accounts, authThrottle } from './chunk-
|
|
6
|
-
import { config } from './chunk-
|
|
3
|
+
import { getEffectiveAuthFlags } from './chunk-3MGEAGHU.mjs';
|
|
4
|
+
import { db } from './chunk-WZDAMCUX.mjs';
|
|
5
|
+
import { users, sessions, passkeys, twoFactors, verifications, accounts, authThrottle } from './chunk-ZQCALTKB.mjs';
|
|
6
|
+
import { config } from './chunk-TMJYAOC2.mjs';
|
|
7
7
|
import { __spreadValues, __spreadProps } from './chunk-3465SI5N.mjs';
|
|
8
8
|
import 'server-only';
|
|
9
9
|
import { betterAuth } from 'better-auth';
|
|
10
10
|
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
|
|
11
11
|
import { createId } from '@paralleldrive/cuid2';
|
|
12
|
-
import {
|
|
12
|
+
import { sql, eq } from 'drizzle-orm';
|
|
13
13
|
import { admin, twoFactor, oneTap } from 'better-auth/plugins';
|
|
14
14
|
import { passkey } from '@better-auth/passkey';
|
|
15
15
|
import { createAuthMiddleware, APIError, getSessionFromCtx } from 'better-auth/api';
|
|
@@ -55,7 +55,7 @@ async function clearDeviceThrottle(fingerprint) {
|
|
|
55
55
|
console.error("auth-throttle clear failed", error);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
-
var EMAIL_FROM =
|
|
58
|
+
var EMAIL_FROM = config.EMAIL_FROM;
|
|
59
59
|
var resend;
|
|
60
60
|
async function getResend() {
|
|
61
61
|
if (!resend) {
|
|
@@ -207,7 +207,13 @@ function createAuth(overrides = {}) {
|
|
|
207
207
|
input: false
|
|
208
208
|
// Prevent users from setting their own role
|
|
209
209
|
}
|
|
210
|
-
}
|
|
210
|
+
},
|
|
211
|
+
// Self-service "Delete account" (dashboard Settings → Danger zone).
|
|
212
|
+
// Credential users confirm with their password; OAuth-only users have
|
|
213
|
+
// no password, so better-auth instead requires a session younger than
|
|
214
|
+
// `freshAge` (default 1 day). Every user-owned table cascades on delete.
|
|
215
|
+
// Impersonation and last-admin guards live in hooks.before below.
|
|
216
|
+
deleteUser: { enabled: true }
|
|
211
217
|
},
|
|
212
218
|
// Advanced options
|
|
213
219
|
advanced: {
|
|
@@ -311,6 +317,20 @@ function createAuth(overrides = {}) {
|
|
|
311
317
|
}
|
|
312
318
|
return;
|
|
313
319
|
}
|
|
320
|
+
if (ctx.path === "/delete-user") {
|
|
321
|
+
const current2 = await getSessionFromCtx(ctx, { disableCookieCache: true });
|
|
322
|
+
if (!current2) return;
|
|
323
|
+
if (current2.session.impersonatedBy) {
|
|
324
|
+
throw new APIError("FORBIDDEN", { message: "Stop impersonating before deleting an account." });
|
|
325
|
+
}
|
|
326
|
+
if (current2.user.role === "admin") {
|
|
327
|
+
const [{ count }] = await db.select({ count: sql`count(*)` }).from(users).where(eq(users.role, "admin"));
|
|
328
|
+
if (Number(count) <= 1) {
|
|
329
|
+
throw new APIError("FORBIDDEN", { message: "You're the only admin. Promote another user to admin first." });
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
314
334
|
if (ctx.path !== "/admin/stop-impersonating") return;
|
|
315
335
|
const current = await getSessionFromCtx(ctx, { disableCookieCache: true });
|
|
316
336
|
if (current == null ? void 0 : current.session.impersonatedBy) {
|
|
@@ -433,6 +453,6 @@ var auth = new Proxy({}, {
|
|
|
433
453
|
}
|
|
434
454
|
});
|
|
435
455
|
|
|
436
|
-
export { auth, createAuth };
|
|
437
|
-
//# sourceMappingURL=chunk-
|
|
438
|
-
//# sourceMappingURL=chunk-
|
|
456
|
+
export { EMAIL_FROM, auth, createAuth, getResend };
|
|
457
|
+
//# sourceMappingURL=chunk-XWVAJXAG.mjs.map
|
|
458
|
+
//# sourceMappingURL=chunk-XWVAJXAG.mjs.map
|