@xk2800/nextjs-template 0.7.1-beta.1 → 0.7.1-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -30
- package/components/auth/deviceCheck.tsx +47 -6
- package/components/auth/oneTap.tsx +5 -5
- package/components/dashboard/admin/adminUserConsentCard.tsx +79 -0
- package/components/dashboard/admin/adminUserDevicesCard.tsx +80 -0
- package/components/dashboard/admin/broadcastActions.tsx +148 -0
- package/components/dashboard/admin/confirmSendDialog.tsx +44 -0
- package/components/dashboard/admin/marketingEmailForm.tsx +115 -0
- package/components/dashboard/admin/marketingSection.tsx +67 -0
- package/components/dashboard/admin/subscribersCard.tsx +62 -0
- package/components/dashboard/admin/systemSettingsForm.tsx +33 -0
- package/components/dashboard/admin/systemSettingsSection.tsx +8 -2
- package/components/dashboard/errorFeedback.tsx +2 -4
- package/components/dashboard/feedbackDialog.tsx +4 -4
- package/components/dashboard/marketingUpdatesCard.tsx +62 -0
- package/components/dashboard/marketingUpdatesSection.tsx +10 -0
- package/components/site/cookie-banner.tsx +109 -7
- package/components/ui/alert-dialog.tsx +1 -1
- package/components/ui/badge.tsx +1 -1
- package/components/ui/card.tsx +1 -1
- package/components/ui/data-table.tsx +4 -1
- package/components/ui/dialog.tsx +1 -1
- package/components/ui/dropdown-menu.tsx +2 -2
- package/components/ui/file-upload.tsx +120 -2
- package/components/ui/select.tsx +189 -0
- package/components/ui/switch.tsx +2 -2
- package/dist/activity/logger.js +36 -0
- package/dist/activity/logger.js.map +1 -1
- package/dist/activity/logger.mjs +4 -4
- package/dist/activity/queries.d.mts +1 -1
- package/dist/activity/queries.d.ts +1 -1
- package/dist/activity/queries.js +36 -0
- package/dist/activity/queries.js.map +1 -1
- package/dist/activity/queries.mjs +3 -3
- package/dist/admin/queries.d.mts +19 -1
- package/dist/admin/queries.d.ts +19 -1
- package/dist/admin/queries.js +64 -0
- package/dist/admin/queries.js.map +1 -1
- package/dist/admin/queries.mjs +26 -5
- package/dist/admin/queries.mjs.map +1 -1
- package/dist/api/feedback.js +53 -2
- package/dist/api/feedback.js.map +1 -1
- package/dist/api/feedback.mjs +9 -8
- package/dist/api/feedback.mjs.map +1 -1
- package/dist/api/marketing.d.mts +36 -0
- package/dist/api/marketing.d.ts +36 -0
- package/dist/api/marketing.js +1357 -0
- package/dist/api/marketing.js.map +1 -0
- package/dist/api/marketing.mjs +170 -0
- package/dist/api/marketing.mjs.map +1 -0
- package/dist/auth/helpers.d.mts +3 -3
- package/dist/auth/helpers.d.ts +3 -3
- package/dist/auth/helpers.js +51 -0
- package/dist/auth/helpers.js.map +1 -1
- package/dist/auth/helpers.mjs +9 -64
- package/dist/auth/helpers.mjs.map +1 -1
- package/dist/auth/index.js +51 -0
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/index.mjs +8 -7
- package/dist/auth-client/index.d.mts +16 -16
- package/dist/auth-client/index.d.ts +16 -16
- package/dist/{chunk-KAEA35OC.mjs → chunk-6MDQRT6U.mjs} +4 -4
- package/dist/{chunk-KAEA35OC.mjs.map → chunk-6MDQRT6U.mjs.map} +1 -1
- package/dist/{chunk-N6ECRCHY.mjs → chunk-6OAHCEDJ.mjs} +4 -3
- package/dist/chunk-6OAHCEDJ.mjs.map +1 -0
- package/dist/chunk-6Z3WUSDJ.mjs +62 -0
- package/dist/chunk-6Z3WUSDJ.mjs.map +1 -0
- package/dist/{chunk-VQ5B4MA7.mjs → chunk-7F2POZM6.mjs} +4 -4
- package/dist/{chunk-VQ5B4MA7.mjs.map → chunk-7F2POZM6.mjs.map} +1 -1
- package/dist/{chunk-XWVAJXAG.mjs → chunk-7QVIOQ47.mjs} +23 -19
- package/dist/chunk-7QVIOQ47.mjs.map +1 -0
- package/dist/chunk-C6RGN6QA.mjs +60 -0
- package/dist/chunk-C6RGN6QA.mjs.map +1 -0
- package/dist/chunk-OVKVD2HH.mjs +25 -0
- package/dist/chunk-OVKVD2HH.mjs.map +1 -0
- package/dist/{chunk-3MGEAGHU.mjs → chunk-P2G23JMY.mjs} +11 -6
- package/dist/chunk-P2G23JMY.mjs.map +1 -0
- package/dist/{chunk-TMJYAOC2.mjs → chunk-TKWNEKK6.mjs} +8 -2
- package/dist/chunk-TKWNEKK6.mjs.map +1 -0
- package/dist/{chunk-ZQCALTKB.mjs → chunk-TR5XFBTD.mjs} +34 -4
- package/dist/chunk-TR5XFBTD.mjs.map +1 -0
- package/dist/{chunk-WZDAMCUX.mjs → chunk-ZJMFE5B2.mjs} +4 -4
- package/dist/{chunk-WZDAMCUX.mjs.map → chunk-ZJMFE5B2.mjs.map} +1 -1
- package/dist/config/env.d.mts +2 -0
- package/dist/config/env.d.ts +2 -0
- package/dist/config/env.js +6 -0
- package/dist/config/env.js.map +1 -1
- package/dist/config/env.mjs +1 -1
- package/dist/db/index.d.mts +1 -1
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.js +36 -0
- package/dist/db/index.js.map +1 -1
- package/dist/db/index.mjs +3 -3
- package/dist/db/schema.d.mts +1 -1
- package/dist/db/schema.d.ts +1 -1
- package/dist/db/schema.js +30 -0
- package/dist/db/schema.js.map +1 -1
- package/dist/db/schema.mjs +1 -1
- package/dist/errors.js +36 -0
- package/dist/errors.js.map +1 -1
- package/dist/errors.mjs +4 -4
- package/dist/marketing/index.d.mts +35 -0
- package/dist/marketing/index.d.ts +35 -0
- package/dist/marketing/index.js +125 -0
- package/dist/marketing/index.js.map +1 -0
- package/dist/marketing/index.mjs +6 -0
- package/dist/marketing/index.mjs.map +1 -0
- package/dist/{schema-UuqxoOzS.d.mts → schema-CN_Y6EXv.d.mts} +148 -2
- package/dist/{schema-UuqxoOzS.d.ts → schema-CN_Y6EXv.d.ts} +148 -2
- package/dist/sessions/queries.js +36 -0
- package/dist/sessions/queries.js.map +1 -1
- package/dist/sessions/queries.mjs +3 -3
- package/dist/settings/queries.d.mts +4 -3
- package/dist/settings/queries.d.ts +4 -3
- package/dist/settings/queries.js +42 -0
- package/dist/settings/queries.js.map +1 -1
- package/dist/settings/queries.mjs +4 -4
- package/dist/users/queries.js +36 -0
- package/dist/users/queries.js.map +1 -1
- package/dist/users/queries.mjs +3 -3
- package/lib/cookie-consent.ts +72 -20
- package/lib/cookie-names.ts +47 -0
- package/lib/device-fingerprint.ts +66 -10
- package/lib/recalculate-columns.ts +2 -0
- package/package.json +28 -3
- package/styles/theme.css +17 -3
- package/dist/chunk-3MGEAGHU.mjs.map +0 -1
- package/dist/chunk-N6ECRCHY.mjs.map +0 -1
- package/dist/chunk-TMJYAOC2.mjs.map +0 -1
- package/dist/chunk-XWVAJXAG.mjs.map +0 -1
- package/dist/chunk-ZQCALTKB.mjs.map +0 -1
|
@@ -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?: ("create" | "list" | "set-role" | "ban" | "impersonate" | "impersonate-admins" | "delete" | "set-password" | "set-email" | "get" | "update")[] | undefined;
|
|
830
|
+
readonly session?: ("list" | "delete" | "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?: ("create" | "list" | "set-role" | "ban" | "impersonate" | "impersonate-admins" | "delete" | "set-password" | "set-email" | "get" | "update")[] | undefined;
|
|
920
|
+
readonly session?: ("list" | "delete" | "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
|
-
banExpires?: Date | null | undefined;
|
|
2427
2426
|
banReason?: string | null | undefined;
|
|
2427
|
+
banExpires?: Date | 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: "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"
|
|
2453
|
+
provider: (string & {}) | "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";
|
|
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: "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"
|
|
2478
|
+
provider: (string & {}) | "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";
|
|
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: "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"
|
|
2505
|
+
provider: (string & {}) | "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";
|
|
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
|
-
banExpires?: Date | null | undefined;
|
|
2537
2536
|
banReason?: string | null | undefined;
|
|
2537
|
+
banExpires?: Date | 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
|
-
banExpires?: Date | null | undefined;
|
|
2585
2584
|
banReason?: string | null | undefined;
|
|
2585
|
+
banExpires?: Date | 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?: ("create" | "list" | "set-role" | "ban" | "impersonate" | "impersonate-admins" | "delete" | "set-password" | "set-email" | "get" | "update")[] | undefined;
|
|
3485
|
+
readonly session?: ("list" | "delete" | "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?: ("create" | "list" | "set-role" | "ban" | "impersonate" | "impersonate-admins" | "delete" | "set-password" | "set-email" | "get" | "update")[] | undefined;
|
|
3575
|
+
readonly session?: ("list" | "delete" | "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
|
-
banExpires?: Date | null | undefined;
|
|
5159
5158
|
banReason?: string | null | undefined;
|
|
5159
|
+
banExpires?: Date | 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
|
-
banExpires?: Date | null | undefined;
|
|
5188
5187
|
banReason?: string | null | undefined;
|
|
5188
|
+
banExpires?: Date | 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?: ("create" | "list" | "set-role" | "ban" | "impersonate" | "impersonate-admins" | "delete" | "set-password" | "set-email" | "get" | "update")[] | undefined;
|
|
830
|
+
readonly session?: ("list" | "delete" | "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?: ("create" | "list" | "set-role" | "ban" | "impersonate" | "impersonate-admins" | "delete" | "set-password" | "set-email" | "get" | "update")[] | undefined;
|
|
920
|
+
readonly session?: ("list" | "delete" | "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
|
-
banExpires?: Date | null | undefined;
|
|
2427
2426
|
banReason?: string | null | undefined;
|
|
2427
|
+
banExpires?: Date | 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: "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"
|
|
2453
|
+
provider: (string & {}) | "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";
|
|
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: "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"
|
|
2478
|
+
provider: (string & {}) | "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";
|
|
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: "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"
|
|
2505
|
+
provider: (string & {}) | "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";
|
|
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
|
-
banExpires?: Date | null | undefined;
|
|
2537
2536
|
banReason?: string | null | undefined;
|
|
2537
|
+
banExpires?: Date | 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
|
-
banExpires?: Date | null | undefined;
|
|
2585
2584
|
banReason?: string | null | undefined;
|
|
2585
|
+
banExpires?: Date | 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?: ("create" | "list" | "set-role" | "ban" | "impersonate" | "impersonate-admins" | "delete" | "set-password" | "set-email" | "get" | "update")[] | undefined;
|
|
3485
|
+
readonly session?: ("list" | "delete" | "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?: ("create" | "list" | "set-role" | "ban" | "impersonate" | "impersonate-admins" | "delete" | "set-password" | "set-email" | "get" | "update")[] | undefined;
|
|
3575
|
+
readonly session?: ("list" | "delete" | "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
|
-
banExpires?: Date | null | undefined;
|
|
5159
5158
|
banReason?: string | null | undefined;
|
|
5159
|
+
banExpires?: Date | 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
|
-
banExpires?: Date | null | undefined;
|
|
5188
5187
|
banReason?: string | null | undefined;
|
|
5188
|
+
banExpires?: Date | null | undefined;
|
|
5189
5189
|
} & {
|
|
5190
5190
|
twoFactorEnabled: boolean | null | undefined;
|
|
5191
5191
|
} & {}>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { db } from './chunk-
|
|
2
|
-
import { errorRefs } from './chunk-
|
|
1
|
+
import { db } from './chunk-ZJMFE5B2.mjs';
|
|
2
|
+
import { errorRefs } from './chunk-TR5XFBTD.mjs';
|
|
3
3
|
import 'server-only';
|
|
4
4
|
import { randomBytes } from 'crypto';
|
|
5
5
|
import { after } from 'next/server';
|
|
@@ -72,5 +72,5 @@ function withActionErrors(action) {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
export { ActionError, lookupErrorDetail, unexpectedErrorMessage, withActionErrors };
|
|
75
|
-
//# sourceMappingURL=chunk-
|
|
76
|
-
//# sourceMappingURL=chunk-
|
|
75
|
+
//# sourceMappingURL=chunk-6MDQRT6U.mjs.map
|
|
76
|
+
//# sourceMappingURL=chunk-6MDQRT6U.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../lib/errors.ts"],"names":[],"mappings":"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","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../lib/errors.ts"],"names":[],"mappings":"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","file":"chunk-6MDQRT6U.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"]}
|
|
@@ -50,12 +50,13 @@ function formatLocation({ country, city }) {
|
|
|
50
50
|
var WINDOW_MS = 15 * 60 * 1e3;
|
|
51
51
|
var MAX = 10;
|
|
52
52
|
var MAX_IP = MAX * 3;
|
|
53
|
+
var RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
53
54
|
function isOverLimit(row, now, max = MAX) {
|
|
54
55
|
if (!row) return false;
|
|
55
56
|
if (now - row.windowStart.getTime() >= WINDOW_MS) return false;
|
|
56
57
|
return row.count >= max;
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
export { MAX_IP, WINDOW_MS, formatDeviceInfo, formatLocation, getClientIp, isOverLimit, lookupGeoLocation, parseUserAgent };
|
|
60
|
-
//# sourceMappingURL=chunk-
|
|
61
|
-
//# sourceMappingURL=chunk-
|
|
60
|
+
export { MAX_IP, RETENTION_MS, WINDOW_MS, formatDeviceInfo, formatLocation, getClientIp, isOverLimit, lookupGeoLocation, parseUserAgent };
|
|
61
|
+
//# sourceMappingURL=chunk-6OAHCEDJ.mjs.map
|
|
62
|
+
//# sourceMappingURL=chunk-6OAHCEDJ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../lib/request-info.ts","../lib/auth-throttle-limits.ts"],"names":[],"mappings":"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","file":"chunk-6OAHCEDJ.mjs","sourcesContent":["import \"server-only\"\nimport { UAParser } from \"ua-parser-js\"\nimport geoip from \"geoip-lite\"\n\nconst countryNames = new Intl.DisplayNames([\"en\"], { type: \"region\" })\n\nexport type DeviceType = \"desktop\" | \"mobile\" | \"tablet\"\n\nexport interface DeviceInfo {\n os: string | null\n browser: string | null\n deviceType: DeviceType\n}\n\nexport interface GeoInfo {\n country: string | null\n city: string | null\n}\n\n/**\n * First address in X-Forwarded-For is the original client — everything after\n * is intermediate proxies. Falls back to null (e.g. local dev with no proxy).\n */\nexport function getClientIp(headers: Headers | undefined | null): string | null {\n const forwardedFor = headers?.get(\"x-forwarded-for\")\n if (forwardedFor) return forwardedFor.split(\",\")[0].trim()\n\n return headers?.get(\"x-real-ip\") ?? null\n}\n\nexport function parseUserAgent(userAgent: string | null | undefined): DeviceInfo {\n if (!userAgent) {\n return { os: null, browser: null, deviceType: \"desktop\" }\n }\n\n const { os, browser, device } = new UAParser(userAgent).getResult()\n\n return {\n os: os.name ? [os.name, os.version].filter(Boolean).join(\" \") : null,\n browser: browser.name ?? null,\n deviceType: device.type === \"mobile\" || device.type === \"tablet\" ? device.type : \"desktop\",\n }\n}\n\n/**\n * Offline lookup (geoip-lite ships its own IP-range database, no network\n * call) — resolves to nulls for private/local addresses like 127.0.0.1.\n */\nexport function lookupGeoLocation(ipAddress: string | null | undefined): GeoInfo {\n if (!ipAddress) return { country: null, city: null }\n\n const geo = geoip.lookup(ipAddress)\n if (!geo) return { country: null, city: null }\n\n let country: string | null = geo.country || null\n if (country) {\n try {\n country = countryNames.of(country) ?? country\n } catch {\n // Unrecognized region code — keep the raw code rather than losing it.\n }\n }\n\n return { country, city: geo.city || null }\n}\n\nexport function formatDeviceInfo({ os, browser, deviceType }: DeviceInfo): string {\n const label = [browser, os].filter(Boolean).join(\" on \")\n const typeLabel = deviceType === \"mobile\" ? \"Mobile\" : deviceType === \"tablet\" ? \"Tablet\" : \"Desktop\"\n\n return label ? `${label} · ${typeLabel}` : `Unknown device · ${typeLabel}`\n}\n\nexport function formatLocation({ country, city }: GeoInfo): string {\n if (!country && !city) return \"Unknown\"\n\n return [city, country].filter(Boolean).join(\", \")\n}\n","// Pure throttle policy — no DB, no `server-only`, so it stays unit-testable.\n// Consumed by lib/auth-throttle.ts (the DB plumbing) and its test.\n\n// Tune per deployment, or lift to env vars if you need it configurable.\nexport const WINDOW_MS = 15 * 60 * 1000 // how long attempts accumulate\nexport const MAX = 10 // failed sign-ins / sign-ups per window before a 429, per fingerprint\n\n// Backstop cap keyed by IP instead of fingerprint — the fingerprint header is\n// client-supplied and unsigned, so it's trivial to omit or randomize per\n// request (see server/auth.ts before-hook). Higher than MAX because an IP can\n// be shared behind NAT/CGNAT/VPN.\n// ponytail: flat multiplier, not a real per-deployment tuning — revisit if\n// legitimate shared-IP traffic ever gets caught in it.\nexport const MAX_IP = MAX * 3\n\n// Rows untouched this long are deleted (lib/auth-throttle.ts). They hold IP,\n// user agent and the last email typed — often for people with no account — so\n// GDPR storage limitation says don't keep them past their use.\nexport const RETENTION_MS = 30 * 24 * 60 * 60 * 1000\n\n// A row whose window has already elapsed counts as \"no row\" — it resets on\n// the next attempt (see recordDeviceAttempt), so the device isn't blocked in\n// the meantime.\nexport function isOverLimit(\n row: { count: number; windowStart: Date } | undefined,\n now: number,\n max: number = MAX,\n): boolean {\n if (!row) return false\n if (now - row.windowStart.getTime() >= WINDOW_MS) return false\n return row.count >= max\n}\n"]}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { auth } from './chunk-7QVIOQ47.mjs';
|
|
2
|
+
import { db } from './chunk-ZJMFE5B2.mjs';
|
|
3
|
+
import { users } from './chunk-TR5XFBTD.mjs';
|
|
4
|
+
import 'server-only';
|
|
5
|
+
import { cache } from 'react';
|
|
6
|
+
import { headers } from 'next/headers';
|
|
7
|
+
import { redirect } from 'next/navigation';
|
|
8
|
+
import { eq } from 'drizzle-orm';
|
|
9
|
+
|
|
10
|
+
var getCurrentSession = cache(async () => {
|
|
11
|
+
const session = await auth.api.getSession({
|
|
12
|
+
headers: await headers()
|
|
13
|
+
});
|
|
14
|
+
return session;
|
|
15
|
+
});
|
|
16
|
+
var requireAuth = cache(async () => {
|
|
17
|
+
var _a;
|
|
18
|
+
const session = await getCurrentSession();
|
|
19
|
+
if (!(session == null ? void 0 : session.user)) {
|
|
20
|
+
redirect("/login");
|
|
21
|
+
}
|
|
22
|
+
const user = await db.select().from(users).where(eq(users.id, session.user.id)).limit(1);
|
|
23
|
+
if ((_a = user[0]) == null ? void 0 : _a.banned) {
|
|
24
|
+
await auth.api.signOut({
|
|
25
|
+
headers: await headers()
|
|
26
|
+
});
|
|
27
|
+
redirect("/login?error=account_banned");
|
|
28
|
+
}
|
|
29
|
+
return session;
|
|
30
|
+
});
|
|
31
|
+
function hasRole(userRole, requiredRole) {
|
|
32
|
+
if (!userRole) return false;
|
|
33
|
+
if (requiredRole === "admin") {
|
|
34
|
+
return userRole === "admin";
|
|
35
|
+
}
|
|
36
|
+
return userRole === "user" || userRole === "admin" || userRole === "tester";
|
|
37
|
+
}
|
|
38
|
+
async function requireRole(requiredRole) {
|
|
39
|
+
const session = await requireAuth();
|
|
40
|
+
if (!hasRole(session.user.role, requiredRole)) {
|
|
41
|
+
redirect("/dashboard");
|
|
42
|
+
}
|
|
43
|
+
return session;
|
|
44
|
+
}
|
|
45
|
+
function normalizeCallbackUrl(value) {
|
|
46
|
+
if (typeof value !== "string" || !value.trim()) return "/dashboard";
|
|
47
|
+
const candidate = value.trim();
|
|
48
|
+
try {
|
|
49
|
+
const appOrigin = new URL(process.env.NEXT_PUBLIC_APP_URL || process.env.BETTER_AUTH_URL || "http://localhost:3000").origin;
|
|
50
|
+
const callbackUrl = new URL(candidate, appOrigin);
|
|
51
|
+
if (callbackUrl.origin !== appOrigin) {
|
|
52
|
+
return "/dashboard";
|
|
53
|
+
}
|
|
54
|
+
return `${callbackUrl.pathname}${callbackUrl.search}${callbackUrl.hash}` || "/dashboard";
|
|
55
|
+
} catch (e) {
|
|
56
|
+
return "/dashboard";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { getCurrentSession, hasRole, normalizeCallbackUrl, requireAuth, requireRole };
|
|
61
|
+
//# sourceMappingURL=chunk-6Z3WUSDJ.mjs.map
|
|
62
|
+
//# sourceMappingURL=chunk-6Z3WUSDJ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../lib/auth-helpers.ts"],"names":[],"mappings":";;;;;;;;;AAgBO,IAAM,iBAAA,GAAoB,MAAM,YAAY;AACjD,EAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,GAAA,CAAI,UAAA,CAAW;AAAA,IACxC,OAAA,EAAS,MAAM,OAAA;AAAQ,GACxB,CAAA;AAED,EAAA,OAAO,OAAA;AACT,CAAC;AASM,IAAM,WAAA,GAAc,MAAM,YAAY;AA/B7C,EAAA,IAAA,EAAA;AAgCE,EAAA,MAAM,OAAA,GAAU,MAAM,iBAAA,EAAkB;AAExC,EAAA,IAAI,EAAC,mCAAS,IAAA,CAAA,EAAM;AAClB,IAAA,QAAA,CAAS,QAAQ,CAAA;AAAA,EACnB;AAGA,EAAA,MAAM,OAAO,MAAM,EAAA,CAChB,QAAO,CACP,IAAA,CAAK,KAAK,CAAA,CACV,KAAA,CAAM,EAAA,CAAG,KAAA,CAAM,IAAI,OAAA,CAAQ,IAAA,CAAK,EAAE,CAAC,CAAA,CACnC,MAAM,CAAC,CAAA;AAEV,EAAA,IAAA,CAAI,EAAA,GAAA,IAAA,CAAK,CAAC,CAAA,KAAN,IAAA,GAAA,MAAA,GAAA,EAAA,CAAS,MAAA,EAAQ;AAEnB,IAAA,MAAM,IAAA,CAAK,IAAI,OAAA,CAAQ;AAAA,MACrB,OAAA,EAAS,MAAM,OAAA;AAAQ,KACxB,CAAA;AACD,IAAA,QAAA,CAAS,6BAA6B,CAAA;AAAA,EACxC;AAEA,EAAA,OAAO,OAAA;AACT,CAAC;AAKM,SAAS,OAAA,CAAQ,UAAqC,YAAA,EAAyC;AACpG,EAAA,IAAI,CAAC,UAAU,OAAO,KAAA;AAEtB,EAAA,IAAI,iBAAiB,OAAA,EAAS;AAC5B,IAAA,OAAO,QAAA,KAAa,OAAA;AAAA,EACtB;AAGA,EAAA,OAAO,QAAA,KAAa,MAAA,IAAU,QAAA,KAAa,OAAA,IAAW,QAAA,KAAa,QAAA;AACrE;AAKA,eAAsB,YAAY,YAAA,EAAgC;AAChE,EAAA,MAAM,OAAA,GAAU,MAAM,WAAA,EAAY;AAElC,EAAA,IAAI,CAAC,OAAA,CAAQ,OAAA,CAAQ,IAAA,CAAK,IAAA,EAAM,YAAY,CAAA,EAAG;AAC7C,IAAA,QAAA,CAAS,YAAY,CAAA;AAAA,EACvB;AAEA,EAAA,OAAO,OAAA;AACT;AAQO,SAAS,qBAAqB,KAAA,EAAmC;AACtE,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,CAAC,KAAA,CAAM,IAAA,IAAQ,OAAO,YAAA;AAEvD,EAAA,MAAM,SAAA,GAAY,MAAM,IAAA,EAAK;AAE7B,EAAA,IAAI;AACF,IAAA,MAAM,SAAA,GAAY,IAAI,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,uBAAuB,OAAA,CAAQ,GAAA,CAAI,eAAA,IAAmB,uBAAuB,CAAA,CAAE,MAAA;AACrH,IAAA,MAAM,WAAA,GAAc,IAAI,GAAA,CAAI,SAAA,EAAW,SAAS,CAAA;AAEhD,IAAA,IAAI,WAAA,CAAY,WAAW,SAAA,EAAW;AACpC,MAAA,OAAO,YAAA;AAAA,IACT;AAEA,IAAA,OAAO,CAAA,EAAG,YAAY,QAAQ,CAAA,EAAG,YAAY,MAAM,CAAA,EAAG,WAAA,CAAY,IAAI,CAAA,CAAA,IAAM,YAAA;AAAA,EAC9E,CAAA,CAAA,OAAQ,CAAA,EAAA;AACN,IAAA,OAAO,YAAA;AAAA,EACT;AACF","file":"chunk-6Z3WUSDJ.mjs","sourcesContent":["import \"server-only\"\nimport { cache } from \"react\"\nimport { auth } from \"../server/auth\"\nimport { headers } from \"next/headers\"\nimport { redirect } from \"next/navigation\"\nimport { db } from \"../server/db\"\nimport { users } from \"../server/db/schema\"\nimport { eq } from \"drizzle-orm\"\n\n/**\n * Get current session (server-side only)\n * Returns session data or null if not authenticated\n *\n * Wrapped in React's cache() so the layout and page (both of which call\n * requireAuth per request) share one auth.api.getSession call instead of two.\n */\nexport const getCurrentSession = cache(async () => {\n const session = await auth.api.getSession({\n headers: await headers()\n })\n\n return session\n})\n\n/**\n * Require authentication - redirect to login if not authenticated\n * Use in server components/layouts that need protection\n *\n * Wrapped in cache() so the layout, page, and any admin layout that all call\n * requireAuth per request share one banned-status DB lookup instead of several.\n */\nexport const requireAuth = cache(async () => {\n const session = await getCurrentSession()\n\n if (!session?.user) {\n redirect('/login')\n }\n\n // Check if user is banned\n const user = await db\n .select()\n .from(users)\n .where(eq(users.id, session.user.id))\n .limit(1)\n\n if (user[0]?.banned) {\n // Sign out the user\n await auth.api.signOut({\n headers: await headers()\n })\n redirect('/login?error=account_banned')\n }\n\n return session\n})\n\n/**\n * Check if user has specific role\n */\nexport function hasRole(userRole: string | null | undefined, requiredRole: 'user' | 'admin'): boolean {\n if (!userRole) return false\n\n if (requiredRole === 'admin') {\n return userRole === 'admin'\n }\n\n // 'user' role check - every role ('user', 'admin', 'tester') has access\n return userRole === 'user' || userRole === 'admin' || userRole === 'tester'\n}\n\n/**\n * Require specific role - throw error if user doesn't have it\n */\nexport async function requireRole(requiredRole: 'user' | 'admin') {\n const session = await requireAuth()\n\n if (!hasRole(session.user.role, requiredRole)) {\n redirect('/dashboard')\n }\n\n return session\n}\n\n/**\n * Normalize a callbackUrl query param to a same-origin path before it's ever\n * passed to redirect() or an auth form's callbackURL. Guards against open\n * redirects (e.g. /login?callbackUrl=https://evil.com) — anything that\n * doesn't resolve to this app's own origin falls back to /dashboard.\n */\nexport function normalizeCallbackUrl(value?: string | string[]): string {\n if (typeof value !== 'string' || !value.trim()) return '/dashboard'\n\n const candidate = value.trim()\n\n try {\n const appOrigin = new URL(process.env.NEXT_PUBLIC_APP_URL || process.env.BETTER_AUTH_URL || 'http://localhost:3000').origin\n const callbackUrl = new URL(candidate, appOrigin)\n\n if (callbackUrl.origin !== appOrigin) {\n return '/dashboard'\n }\n\n return `${callbackUrl.pathname}${callbackUrl.search}${callbackUrl.hash}` || '/dashboard'\n } catch {\n return '/dashboard'\n }\n}\n\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { db } from './chunk-
|
|
2
|
-
import { activityLogs } from './chunk-
|
|
1
|
+
import { db } from './chunk-ZJMFE5B2.mjs';
|
|
2
|
+
import { activityLogs } from './chunk-TR5XFBTD.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-7F2POZM6.mjs.map
|
|
41
|
+
//# sourceMappingURL=chunk-7F2POZM6.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-7F2POZM6.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,15 +1,16 @@
|
|
|
1
|
-
import { logActivity } from './chunk-
|
|
2
|
-
import { getClientIp, parseUserAgent, lookupGeoLocation, formatLocation, formatDeviceInfo, WINDOW_MS, isOverLimit, MAX_IP } from './chunk-
|
|
3
|
-
import { getEffectiveAuthFlags } from './chunk-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { logActivity } from './chunk-7F2POZM6.mjs';
|
|
2
|
+
import { getClientIp, parseUserAgent, lookupGeoLocation, formatLocation, formatDeviceInfo, WINDOW_MS, isOverLimit, MAX_IP, RETENTION_MS } from './chunk-6OAHCEDJ.mjs';
|
|
3
|
+
import { getEffectiveAuthFlags } from './chunk-P2G23JMY.mjs';
|
|
4
|
+
import { getResend, EMAIL_FROM } from './chunk-OVKVD2HH.mjs';
|
|
5
|
+
import { db } from './chunk-ZJMFE5B2.mjs';
|
|
6
|
+
import { users, sessions, passkeys, twoFactors, verifications, accounts, authThrottle } from './chunk-TR5XFBTD.mjs';
|
|
7
|
+
import { config } from './chunk-TKWNEKK6.mjs';
|
|
7
8
|
import { __spreadValues, __spreadProps } from './chunk-3465SI5N.mjs';
|
|
8
9
|
import 'server-only';
|
|
9
10
|
import { betterAuth } from 'better-auth';
|
|
10
11
|
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
|
|
11
12
|
import { createId } from '@paralleldrive/cuid2';
|
|
12
|
-
import { sql, eq } from 'drizzle-orm';
|
|
13
|
+
import { sql, eq, lt } from 'drizzle-orm';
|
|
13
14
|
import { admin, twoFactor, oneTap } from 'better-auth/plugins';
|
|
14
15
|
import { passkey } from '@better-auth/passkey';
|
|
15
16
|
import { createAuthMiddleware, APIError, getSessionFromCtx } from 'better-auth/api';
|
|
@@ -47,6 +48,18 @@ async function recordDeviceAttempt(fingerprint, meta) {
|
|
|
47
48
|
} catch (error) {
|
|
48
49
|
console.error("auth-throttle write failed", error);
|
|
49
50
|
}
|
|
51
|
+
await pruneStaleRows(now);
|
|
52
|
+
}
|
|
53
|
+
var PRUNE_EVERY_MS = 60 * 60 * 1e3;
|
|
54
|
+
var lastPrune = 0;
|
|
55
|
+
async function pruneStaleRows(now = /* @__PURE__ */ new Date()) {
|
|
56
|
+
if (now.getTime() - lastPrune < PRUNE_EVERY_MS) return;
|
|
57
|
+
lastPrune = now.getTime();
|
|
58
|
+
try {
|
|
59
|
+
await db.delete(authThrottle).where(lt(authThrottle.lastAttemptAt, new Date(now.getTime() - RETENTION_MS)));
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error("auth-throttle prune failed", error);
|
|
62
|
+
}
|
|
50
63
|
}
|
|
51
64
|
async function clearDeviceThrottle(fingerprint) {
|
|
52
65
|
try {
|
|
@@ -55,15 +68,6 @@ async function clearDeviceThrottle(fingerprint) {
|
|
|
55
68
|
console.error("auth-throttle clear failed", error);
|
|
56
69
|
}
|
|
57
70
|
}
|
|
58
|
-
var EMAIL_FROM = config.EMAIL_FROM;
|
|
59
|
-
var resend;
|
|
60
|
-
async function getResend() {
|
|
61
|
-
if (!resend) {
|
|
62
|
-
const { Resend } = await import('resend');
|
|
63
|
-
resend = new Resend(config.RESEND_API_KEY);
|
|
64
|
-
}
|
|
65
|
-
return resend;
|
|
66
|
-
}
|
|
67
71
|
|
|
68
72
|
// server/auth.ts
|
|
69
73
|
async function logFailedLogin(ctx) {
|
|
@@ -453,6 +457,6 @@ var auth = new Proxy({}, {
|
|
|
453
457
|
}
|
|
454
458
|
});
|
|
455
459
|
|
|
456
|
-
export {
|
|
457
|
-
//# sourceMappingURL=chunk-
|
|
458
|
-
//# sourceMappingURL=chunk-
|
|
460
|
+
export { auth, createAuth };
|
|
461
|
+
//# sourceMappingURL=chunk-7QVIOQ47.mjs.map
|
|
462
|
+
//# sourceMappingURL=chunk-7QVIOQ47.mjs.map
|