@hammadj/better-auth-core 1.5.0-beta.9
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/.turbo/turbo-build.log +266 -0
- package/.turbo/turbo-test.log +2 -0
- package/LICENSE.md +20 -0
- package/dist/api/index.d.mts +181 -0
- package/dist/api/index.mjs +34 -0
- package/dist/api/index.mjs.map +1 -0
- package/dist/async_hooks/index.d.mts +7 -0
- package/dist/async_hooks/index.mjs +22 -0
- package/dist/async_hooks/index.mjs.map +1 -0
- package/dist/async_hooks/pure.index.d.mts +7 -0
- package/dist/async_hooks/pure.index.mjs +35 -0
- package/dist/async_hooks/pure.index.mjs.map +1 -0
- package/dist/context/endpoint-context.d.mts +19 -0
- package/dist/context/endpoint-context.mjs +32 -0
- package/dist/context/endpoint-context.mjs.map +1 -0
- package/dist/context/global.d.mts +7 -0
- package/dist/context/global.mjs +38 -0
- package/dist/context/global.mjs.map +1 -0
- package/dist/context/index.d.mts +5 -0
- package/dist/context/index.mjs +6 -0
- package/dist/context/request-state.d.mts +26 -0
- package/dist/context/request-state.mjs +50 -0
- package/dist/context/request-state.mjs.map +1 -0
- package/dist/context/transaction.d.mts +25 -0
- package/dist/context/transaction.mjs +96 -0
- package/dist/context/transaction.mjs.map +1 -0
- package/dist/db/adapter/factory.d.mts +28 -0
- package/dist/db/adapter/factory.mjs +716 -0
- package/dist/db/adapter/factory.mjs.map +1 -0
- package/dist/db/adapter/get-default-field-name.d.mts +19 -0
- package/dist/db/adapter/get-default-field-name.mjs +39 -0
- package/dist/db/adapter/get-default-field-name.mjs.map +1 -0
- package/dist/db/adapter/get-default-model-name.d.mts +13 -0
- package/dist/db/adapter/get-default-model-name.mjs +33 -0
- package/dist/db/adapter/get-default-model-name.mjs.map +1 -0
- package/dist/db/adapter/get-field-attributes.d.mts +30 -0
- package/dist/db/adapter/get-field-attributes.mjs +40 -0
- package/dist/db/adapter/get-field-attributes.mjs.map +1 -0
- package/dist/db/adapter/get-field-name.d.mts +19 -0
- package/dist/db/adapter/get-field-name.mjs +34 -0
- package/dist/db/adapter/get-field-name.mjs.map +1 -0
- package/dist/db/adapter/get-id-field.d.mts +40 -0
- package/dist/db/adapter/get-id-field.mjs +68 -0
- package/dist/db/adapter/get-id-field.mjs.map +1 -0
- package/dist/db/adapter/get-model-name.d.mts +13 -0
- package/dist/db/adapter/get-model-name.mjs +24 -0
- package/dist/db/adapter/get-model-name.mjs.map +1 -0
- package/dist/db/adapter/index.d.mts +515 -0
- package/dist/db/adapter/index.mjs +10 -0
- package/dist/db/adapter/types.d.mts +140 -0
- package/dist/db/adapter/utils.d.mts +8 -0
- package/dist/db/adapter/utils.mjs +39 -0
- package/dist/db/adapter/utils.mjs.map +1 -0
- package/dist/db/get-tables.d.mts +9 -0
- package/dist/db/get-tables.mjs +267 -0
- package/dist/db/get-tables.mjs.map +1 -0
- package/dist/db/index.d.mts +10 -0
- package/dist/db/index.mjs +9 -0
- package/dist/db/plugin.d.mts +13 -0
- package/dist/db/schema/account.d.mts +27 -0
- package/dist/db/schema/account.mjs +20 -0
- package/dist/db/schema/account.mjs.map +1 -0
- package/dist/db/schema/rate-limit.d.mts +15 -0
- package/dist/db/schema/rate-limit.mjs +12 -0
- package/dist/db/schema/rate-limit.mjs.map +1 -0
- package/dist/db/schema/session.d.mts +22 -0
- package/dist/db/schema/session.mjs +15 -0
- package/dist/db/schema/session.mjs.map +1 -0
- package/dist/db/schema/shared.d.mts +11 -0
- package/dist/db/schema/shared.mjs +12 -0
- package/dist/db/schema/shared.mjs.map +1 -0
- package/dist/db/schema/user.d.mts +21 -0
- package/dist/db/schema/user.mjs +14 -0
- package/dist/db/schema/user.mjs.map +1 -0
- package/dist/db/schema/verification.d.mts +20 -0
- package/dist/db/schema/verification.mjs +13 -0
- package/dist/db/schema/verification.mjs.map +1 -0
- package/dist/db/type.d.mts +147 -0
- package/dist/env/color-depth.d.mts +5 -0
- package/dist/env/color-depth.mjs +89 -0
- package/dist/env/color-depth.mjs.map +1 -0
- package/dist/env/env-impl.d.mts +33 -0
- package/dist/env/env-impl.mjs +83 -0
- package/dist/env/env-impl.mjs.map +1 -0
- package/dist/env/index.d.mts +4 -0
- package/dist/env/index.mjs +5 -0
- package/dist/env/logger.d.mts +49 -0
- package/dist/env/logger.mjs +82 -0
- package/dist/env/logger.mjs.map +1 -0
- package/dist/error/codes.d.mts +199 -0
- package/dist/error/codes.mjs +57 -0
- package/dist/error/codes.mjs.map +1 -0
- package/dist/error/index.d.mts +20 -0
- package/dist/error/index.mjs +30 -0
- package/dist/error/index.mjs.map +1 -0
- package/dist/index.d.mts +8 -0
- package/dist/index.mjs +1 -0
- package/dist/oauth2/client-credentials-token.d.mts +37 -0
- package/dist/oauth2/client-credentials-token.mjs +55 -0
- package/dist/oauth2/client-credentials-token.mjs.map +1 -0
- package/dist/oauth2/create-authorization-url.d.mts +46 -0
- package/dist/oauth2/create-authorization-url.mjs +43 -0
- package/dist/oauth2/create-authorization-url.mjs.map +1 -0
- package/dist/oauth2/index.d.mts +8 -0
- package/dist/oauth2/index.mjs +8 -0
- package/dist/oauth2/oauth-provider.d.mts +195 -0
- package/dist/oauth2/refresh-access-token.d.mts +36 -0
- package/dist/oauth2/refresh-access-token.mjs +59 -0
- package/dist/oauth2/refresh-access-token.mjs.map +1 -0
- package/dist/oauth2/utils.d.mts +8 -0
- package/dist/oauth2/utils.mjs +28 -0
- package/dist/oauth2/utils.mjs.map +1 -0
- package/dist/oauth2/validate-authorization-code.d.mts +56 -0
- package/dist/oauth2/validate-authorization-code.mjs +72 -0
- package/dist/oauth2/validate-authorization-code.mjs.map +1 -0
- package/dist/oauth2/verify.d.mts +43 -0
- package/dist/oauth2/verify.mjs +96 -0
- package/dist/oauth2/verify.mjs.map +1 -0
- package/dist/social-providers/apple.d.mts +120 -0
- package/dist/social-providers/apple.mjs +105 -0
- package/dist/social-providers/apple.mjs.map +1 -0
- package/dist/social-providers/atlassian.d.mts +73 -0
- package/dist/social-providers/atlassian.mjs +84 -0
- package/dist/social-providers/atlassian.mjs.map +1 -0
- package/dist/social-providers/cognito.d.mts +88 -0
- package/dist/social-providers/cognito.mjs +166 -0
- package/dist/social-providers/cognito.mjs.map +1 -0
- package/dist/social-providers/discord.d.mts +127 -0
- package/dist/social-providers/discord.mjs +65 -0
- package/dist/social-providers/discord.mjs.map +1 -0
- package/dist/social-providers/dropbox.d.mts +72 -0
- package/dist/social-providers/dropbox.mjs +76 -0
- package/dist/social-providers/dropbox.mjs.map +1 -0
- package/dist/social-providers/facebook.d.mts +82 -0
- package/dist/social-providers/facebook.mjs +121 -0
- package/dist/social-providers/facebook.mjs.map +1 -0
- package/dist/social-providers/figma.d.mts +64 -0
- package/dist/social-providers/figma.mjs +87 -0
- package/dist/social-providers/figma.mjs.map +1 -0
- package/dist/social-providers/github.d.mts +105 -0
- package/dist/social-providers/github.mjs +97 -0
- package/dist/social-providers/github.mjs.map +1 -0
- package/dist/social-providers/gitlab.d.mts +126 -0
- package/dist/social-providers/gitlab.mjs +83 -0
- package/dist/social-providers/gitlab.mjs.map +1 -0
- package/dist/social-providers/google.d.mts +100 -0
- package/dist/social-providers/google.mjs +109 -0
- package/dist/social-providers/google.mjs.map +1 -0
- package/dist/social-providers/huggingface.d.mts +86 -0
- package/dist/social-providers/huggingface.mjs +76 -0
- package/dist/social-providers/huggingface.mjs.map +1 -0
- package/dist/social-providers/index.d.mts +1725 -0
- package/dist/social-providers/index.mjs +77 -0
- package/dist/social-providers/index.mjs.map +1 -0
- package/dist/social-providers/kakao.d.mts +164 -0
- package/dist/social-providers/kakao.mjs +73 -0
- package/dist/social-providers/kakao.mjs.map +1 -0
- package/dist/social-providers/kick.d.mts +76 -0
- package/dist/social-providers/kick.mjs +72 -0
- package/dist/social-providers/kick.mjs.map +1 -0
- package/dist/social-providers/line.d.mts +108 -0
- package/dist/social-providers/line.mjs +114 -0
- package/dist/social-providers/line.mjs.map +1 -0
- package/dist/social-providers/linear.d.mts +71 -0
- package/dist/social-providers/linear.mjs +89 -0
- package/dist/social-providers/linear.mjs.map +1 -0
- package/dist/social-providers/linkedin.d.mts +70 -0
- package/dist/social-providers/linkedin.mjs +77 -0
- package/dist/social-providers/linkedin.mjs.map +1 -0
- package/dist/social-providers/microsoft-entra-id.d.mts +175 -0
- package/dist/social-providers/microsoft-entra-id.mjs +107 -0
- package/dist/social-providers/microsoft-entra-id.mjs.map +1 -0
- package/dist/social-providers/naver.d.mts +95 -0
- package/dist/social-providers/naver.mjs +68 -0
- package/dist/social-providers/naver.mjs.map +1 -0
- package/dist/social-providers/notion.d.mts +67 -0
- package/dist/social-providers/notion.mjs +76 -0
- package/dist/social-providers/notion.mjs.map +1 -0
- package/dist/social-providers/paybin.d.mts +74 -0
- package/dist/social-providers/paybin.mjs +86 -0
- package/dist/social-providers/paybin.mjs.map +1 -0
- package/dist/social-providers/paypal.d.mts +132 -0
- package/dist/social-providers/paypal.mjs +145 -0
- package/dist/social-providers/paypal.mjs.map +1 -0
- package/dist/social-providers/polar.d.mts +77 -0
- package/dist/social-providers/polar.mjs +74 -0
- package/dist/social-providers/polar.mjs.map +1 -0
- package/dist/social-providers/reddit.d.mts +65 -0
- package/dist/social-providers/reddit.mjs +84 -0
- package/dist/social-providers/reddit.mjs.map +1 -0
- package/dist/social-providers/roblox.d.mts +73 -0
- package/dist/social-providers/roblox.mjs +60 -0
- package/dist/social-providers/roblox.mjs.map +1 -0
- package/dist/social-providers/salesforce.d.mts +82 -0
- package/dist/social-providers/salesforce.mjs +92 -0
- package/dist/social-providers/salesforce.mjs.map +1 -0
- package/dist/social-providers/slack.d.mts +86 -0
- package/dist/social-providers/slack.mjs +69 -0
- package/dist/social-providers/slack.mjs.map +1 -0
- package/dist/social-providers/spotify.d.mts +66 -0
- package/dist/social-providers/spotify.mjs +72 -0
- package/dist/social-providers/spotify.mjs.map +1 -0
- package/dist/social-providers/tiktok.d.mts +171 -0
- package/dist/social-providers/tiktok.mjs +63 -0
- package/dist/social-providers/tiktok.mjs.map +1 -0
- package/dist/social-providers/twitch.d.mts +82 -0
- package/dist/social-providers/twitch.mjs +79 -0
- package/dist/social-providers/twitch.mjs.map +1 -0
- package/dist/social-providers/twitter.d.mts +129 -0
- package/dist/social-providers/twitter.mjs +88 -0
- package/dist/social-providers/twitter.mjs.map +1 -0
- package/dist/social-providers/vercel.d.mts +65 -0
- package/dist/social-providers/vercel.mjs +62 -0
- package/dist/social-providers/vercel.mjs.map +1 -0
- package/dist/social-providers/vk.d.mts +73 -0
- package/dist/social-providers/vk.mjs +84 -0
- package/dist/social-providers/vk.mjs.map +1 -0
- package/dist/social-providers/zoom.d.mts +173 -0
- package/dist/social-providers/zoom.mjs +73 -0
- package/dist/social-providers/zoom.mjs.map +1 -0
- package/dist/types/context.d.mts +267 -0
- package/dist/types/cookie.d.mts +16 -0
- package/dist/types/helper.d.mts +10 -0
- package/dist/types/index.d.mts +8 -0
- package/dist/types/init-options.d.mts +1314 -0
- package/dist/types/plugin-client.d.mts +112 -0
- package/dist/types/plugin.d.mts +125 -0
- package/dist/utils/db.d.mts +12 -0
- package/dist/utils/db.mjs +17 -0
- package/dist/utils/db.mjs.map +1 -0
- package/dist/utils/deprecate.d.mts +10 -0
- package/dist/utils/deprecate.mjs +18 -0
- package/dist/utils/deprecate.mjs.map +1 -0
- package/dist/utils/error-codes.d.mts +13 -0
- package/dist/utils/error-codes.mjs +12 -0
- package/dist/utils/error-codes.mjs.map +1 -0
- package/dist/utils/id.d.mts +5 -0
- package/dist/utils/id.mjs +10 -0
- package/dist/utils/id.mjs.map +1 -0
- package/dist/utils/ip.d.mts +55 -0
- package/dist/utils/ip.mjs +119 -0
- package/dist/utils/ip.mjs.map +1 -0
- package/dist/utils/json.d.mts +5 -0
- package/dist/utils/json.mjs +26 -0
- package/dist/utils/json.mjs.map +1 -0
- package/dist/utils/string.d.mts +5 -0
- package/dist/utils/string.mjs +8 -0
- package/dist/utils/string.mjs.map +1 -0
- package/dist/utils/url.d.mts +21 -0
- package/dist/utils/url.mjs +33 -0
- package/dist/utils/url.mjs.map +1 -0
- package/package.json +147 -0
- package/src/api/index.ts +106 -0
- package/src/async_hooks/index.ts +40 -0
- package/src/async_hooks/pure.index.ts +46 -0
- package/src/context/endpoint-context.ts +50 -0
- package/src/context/global.ts +57 -0
- package/src/context/index.ts +23 -0
- package/src/context/request-state.test.ts +94 -0
- package/src/context/request-state.ts +91 -0
- package/src/context/transaction.ts +136 -0
- package/src/db/adapter/factory.ts +1362 -0
- package/src/db/adapter/get-default-field-name.ts +59 -0
- package/src/db/adapter/get-default-model-name.ts +51 -0
- package/src/db/adapter/get-field-attributes.ts +62 -0
- package/src/db/adapter/get-field-name.ts +43 -0
- package/src/db/adapter/get-id-field.ts +141 -0
- package/src/db/adapter/get-model-name.ts +36 -0
- package/src/db/adapter/index.ts +554 -0
- package/src/db/adapter/types.ts +171 -0
- package/src/db/adapter/utils.ts +61 -0
- package/src/db/get-tables.ts +296 -0
- package/src/db/index.ts +18 -0
- package/src/db/plugin.ts +11 -0
- package/src/db/schema/account.ts +34 -0
- package/src/db/schema/rate-limit.ts +21 -0
- package/src/db/schema/session.ts +17 -0
- package/src/db/schema/shared.ts +7 -0
- package/src/db/schema/user.ts +16 -0
- package/src/db/schema/verification.ts +15 -0
- package/src/db/test/get-tables.test.ts +116 -0
- package/src/db/type.ts +180 -0
- package/src/env/color-depth.ts +172 -0
- package/src/env/env-impl.ts +124 -0
- package/src/env/index.ts +23 -0
- package/src/env/logger.test.ts +34 -0
- package/src/env/logger.ts +145 -0
- package/src/error/codes.ts +58 -0
- package/src/error/index.ts +35 -0
- package/src/index.ts +1 -0
- package/src/oauth2/client-credentials-token.ts +102 -0
- package/src/oauth2/create-authorization-url.ts +87 -0
- package/src/oauth2/index.ts +26 -0
- package/src/oauth2/oauth-provider.ts +222 -0
- package/src/oauth2/refresh-access-token.ts +124 -0
- package/src/oauth2/utils.ts +38 -0
- package/src/oauth2/validate-authorization-code.ts +149 -0
- package/src/oauth2/validate-token.test.ts +174 -0
- package/src/oauth2/verify.ts +221 -0
- package/src/social-providers/apple.ts +223 -0
- package/src/social-providers/atlassian.ts +132 -0
- package/src/social-providers/cognito.ts +279 -0
- package/src/social-providers/discord.ts +169 -0
- package/src/social-providers/dropbox.ts +112 -0
- package/src/social-providers/facebook.ts +206 -0
- package/src/social-providers/figma.ts +117 -0
- package/src/social-providers/github.ts +184 -0
- package/src/social-providers/gitlab.ts +155 -0
- package/src/social-providers/google.ts +199 -0
- package/src/social-providers/huggingface.ts +118 -0
- package/src/social-providers/index.ts +127 -0
- package/src/social-providers/kakao.ts +178 -0
- package/src/social-providers/kick.ts +109 -0
- package/src/social-providers/line.ts +169 -0
- package/src/social-providers/linear.ts +121 -0
- package/src/social-providers/linkedin.ts +110 -0
- package/src/social-providers/microsoft-entra-id.ts +259 -0
- package/src/social-providers/naver.ts +112 -0
- package/src/social-providers/notion.ts +108 -0
- package/src/social-providers/paybin.ts +122 -0
- package/src/social-providers/paypal.ts +263 -0
- package/src/social-providers/polar.ts +110 -0
- package/src/social-providers/reddit.ts +122 -0
- package/src/social-providers/roblox.ts +111 -0
- package/src/social-providers/salesforce.ts +159 -0
- package/src/social-providers/slack.ts +111 -0
- package/src/social-providers/spotify.ts +93 -0
- package/src/social-providers/tiktok.ts +209 -0
- package/src/social-providers/twitch.ts +111 -0
- package/src/social-providers/twitter.ts +198 -0
- package/src/social-providers/vercel.ts +87 -0
- package/src/social-providers/vk.ts +124 -0
- package/src/social-providers/zoom.ts +238 -0
- package/src/types/context.ts +396 -0
- package/src/types/cookie.ts +10 -0
- package/src/types/helper.ts +26 -0
- package/src/types/index.ts +32 -0
- package/src/types/init-options.ts +1529 -0
- package/src/types/plugin-client.ts +127 -0
- package/src/types/plugin.ts +157 -0
- package/src/utils/db.ts +20 -0
- package/src/utils/deprecate.test.ts +72 -0
- package/src/utils/deprecate.ts +21 -0
- package/src/utils/error-codes.ts +65 -0
- package/src/utils/id.ts +5 -0
- package/src/utils/ip.test.ts +255 -0
- package/src/utils/ip.ts +211 -0
- package/src/utils/json.ts +25 -0
- package/src/utils/string.ts +3 -0
- package/src/utils/url.ts +43 -0
- package/tsconfig.json +7 -0
- package/tsdown.config.ts +35 -0
- package/vitest.config.ts +3 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { LiteralString } from "./helper.mjs";
|
|
2
|
+
import { BetterAuthPlugin } from "./plugin.mjs";
|
|
3
|
+
import { BetterAuthOptions } from "./init-options.mjs";
|
|
4
|
+
import { BetterFetch, BetterFetchOption, BetterFetchPlugin } from "@better-fetch/fetch";
|
|
5
|
+
import { Atom, WritableAtom } from "nanostores";
|
|
6
|
+
|
|
7
|
+
//#region src/types/plugin-client.d.ts
|
|
8
|
+
interface ClientStore {
|
|
9
|
+
notify: (signal: string) => void;
|
|
10
|
+
listen: (signal: string, listener: () => void) => void;
|
|
11
|
+
atoms: Record<string, WritableAtom<any>>;
|
|
12
|
+
}
|
|
13
|
+
type ClientAtomListener = {
|
|
14
|
+
matcher: (path: string) => boolean;
|
|
15
|
+
signal: "$sessionSignal" | Omit<string, "$sessionSignal">;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Better-Fetch options but with additional options for the auth-client.
|
|
19
|
+
*/
|
|
20
|
+
type ClientFetchOption<Body = any, Query extends Record<string, any> = any, Params extends Record<string, any> | Array<string> | undefined = any, Res = any> = BetterFetchOption<Body, Query, Params, Res> & {
|
|
21
|
+
/**
|
|
22
|
+
* Certain endpoints, upon successful response, will trigger atom signals and thus rerendering all hooks related to that atom.
|
|
23
|
+
*
|
|
24
|
+
* This option is useful when you want to skip hook rerenders.
|
|
25
|
+
*/
|
|
26
|
+
disableSignal?: boolean | undefined;
|
|
27
|
+
};
|
|
28
|
+
interface RevalidateOptions {
|
|
29
|
+
/**
|
|
30
|
+
* A time interval (in seconds) after which the session will be re-fetched.
|
|
31
|
+
* If set to `0` (default), the session is not polled.
|
|
32
|
+
*
|
|
33
|
+
* This helps prevent session expiry during idle periods by periodically
|
|
34
|
+
* refreshing the session.
|
|
35
|
+
*
|
|
36
|
+
* @default 0
|
|
37
|
+
*/
|
|
38
|
+
refetchInterval?: number | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Automatically refetch the session when the user switches back to the window/tab.
|
|
41
|
+
* This option activates this behavior if set to `true` (default).
|
|
42
|
+
*
|
|
43
|
+
* Prevents expired sessions when users switch tabs and come back later.
|
|
44
|
+
*
|
|
45
|
+
* @default true
|
|
46
|
+
*/
|
|
47
|
+
refetchOnWindowFocus?: boolean | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Set to `false` to stop polling when the device has no internet access
|
|
50
|
+
* (determined by `navigator.onLine`).
|
|
51
|
+
*
|
|
52
|
+
* @default false
|
|
53
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/NavigatorOnLine/onLine
|
|
54
|
+
*/
|
|
55
|
+
refetchWhenOffline?: boolean | undefined;
|
|
56
|
+
}
|
|
57
|
+
interface BetterAuthClientOptions {
|
|
58
|
+
fetchOptions?: ClientFetchOption | undefined;
|
|
59
|
+
plugins?: BetterAuthClientPlugin[] | undefined;
|
|
60
|
+
baseURL?: string | undefined;
|
|
61
|
+
basePath?: string | undefined;
|
|
62
|
+
disableDefaultFetchPlugins?: boolean | undefined;
|
|
63
|
+
$InferAuth?: BetterAuthOptions | undefined;
|
|
64
|
+
sessionOptions?: RevalidateOptions | undefined;
|
|
65
|
+
}
|
|
66
|
+
interface BetterAuthClientPlugin {
|
|
67
|
+
id: LiteralString;
|
|
68
|
+
/**
|
|
69
|
+
* only used for type inference. don't pass the
|
|
70
|
+
* actual plugin
|
|
71
|
+
*/
|
|
72
|
+
$InferServerPlugin?: BetterAuthPlugin | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* Custom actions
|
|
75
|
+
*/
|
|
76
|
+
getActions?: ($fetch: BetterFetch, $store: ClientStore,
|
|
77
|
+
/**
|
|
78
|
+
* better-auth client options
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
options: BetterAuthClientOptions | undefined) => Record<string, any>;
|
|
82
|
+
/**
|
|
83
|
+
* State atoms that'll be resolved by each framework
|
|
84
|
+
* auth store.
|
|
85
|
+
*/
|
|
86
|
+
getAtoms?: (($fetch: BetterFetch) => Record<string, Atom<any>>) | undefined;
|
|
87
|
+
/**
|
|
88
|
+
* specify path methods for server plugin inferred
|
|
89
|
+
* endpoints to force a specific method.
|
|
90
|
+
*/
|
|
91
|
+
pathMethods?: Record<string, "POST" | "GET"> | undefined;
|
|
92
|
+
/**
|
|
93
|
+
* Better fetch plugins
|
|
94
|
+
*/
|
|
95
|
+
fetchPlugins?: BetterFetchPlugin[] | undefined;
|
|
96
|
+
/**
|
|
97
|
+
* a list of recaller based on a matcher function.
|
|
98
|
+
* The signal name needs to match a signal in this
|
|
99
|
+
* plugin or any plugin the user might have added.
|
|
100
|
+
*/
|
|
101
|
+
atomListeners?: ClientAtomListener[] | undefined;
|
|
102
|
+
/**
|
|
103
|
+
* The error codes returned by the plugin
|
|
104
|
+
*/
|
|
105
|
+
$ERROR_CODES?: Record<string, {
|
|
106
|
+
code: string;
|
|
107
|
+
message: string;
|
|
108
|
+
}>;
|
|
109
|
+
}
|
|
110
|
+
//#endregion
|
|
111
|
+
export { BetterAuthClientOptions, BetterAuthClientPlugin, ClientAtomListener, ClientFetchOption, ClientStore };
|
|
112
|
+
//# sourceMappingURL=plugin-client.d.mts.map
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { BetterAuthPluginDBSchema } from "../db/plugin.mjs";
|
|
2
|
+
import "../db/index.mjs";
|
|
3
|
+
import { Awaitable, LiteralString } from "./helper.mjs";
|
|
4
|
+
import { BetterAuthOptions } from "./init-options.mjs";
|
|
5
|
+
import { AuthContext } from "./context.mjs";
|
|
6
|
+
import { AuthMiddleware } from "../api/index.mjs";
|
|
7
|
+
import { Endpoint, EndpointContext, InputContext, Middleware } from "better-call";
|
|
8
|
+
import { Migration } from "kysely";
|
|
9
|
+
|
|
10
|
+
//#region src/types/plugin.d.ts
|
|
11
|
+
type DeepPartial<T> = T extends Function ? T : T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T;
|
|
12
|
+
type HookEndpointContext = Partial<EndpointContext<string, any> & Omit<InputContext<string, any>, "method">> & {
|
|
13
|
+
path?: string;
|
|
14
|
+
context: AuthContext & {
|
|
15
|
+
returned?: unknown | undefined;
|
|
16
|
+
responseHeaders?: Headers | undefined;
|
|
17
|
+
};
|
|
18
|
+
headers?: Headers | undefined;
|
|
19
|
+
};
|
|
20
|
+
type BetterAuthPlugin = {
|
|
21
|
+
id: LiteralString;
|
|
22
|
+
/**
|
|
23
|
+
* The init function is called when the plugin is initialized.
|
|
24
|
+
* You can return a new context or modify the existing context.
|
|
25
|
+
*/
|
|
26
|
+
init?: ((ctx: AuthContext) => Awaitable<{
|
|
27
|
+
context?: DeepPartial<Omit<AuthContext, "options">>;
|
|
28
|
+
options?: Partial<BetterAuthOptions>;
|
|
29
|
+
}> | void | Promise<void>) | undefined;
|
|
30
|
+
endpoints?: {
|
|
31
|
+
[key: string]: Endpoint;
|
|
32
|
+
} | undefined;
|
|
33
|
+
middlewares?: {
|
|
34
|
+
path: string;
|
|
35
|
+
middleware: Middleware;
|
|
36
|
+
}[] | undefined;
|
|
37
|
+
onRequest?: ((request: Request, ctx: AuthContext) => Promise<{
|
|
38
|
+
response: Response;
|
|
39
|
+
} | {
|
|
40
|
+
request: Request;
|
|
41
|
+
} | void>) | undefined;
|
|
42
|
+
onResponse?: ((response: Response, ctx: AuthContext) => Promise<{
|
|
43
|
+
response: Response;
|
|
44
|
+
} | void>) | undefined;
|
|
45
|
+
hooks?: {
|
|
46
|
+
before?: {
|
|
47
|
+
matcher: (context: HookEndpointContext) => boolean;
|
|
48
|
+
handler: AuthMiddleware;
|
|
49
|
+
}[];
|
|
50
|
+
after?: {
|
|
51
|
+
matcher: (context: HookEndpointContext) => boolean;
|
|
52
|
+
handler: AuthMiddleware;
|
|
53
|
+
}[];
|
|
54
|
+
} | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* Schema the plugin needs
|
|
57
|
+
*
|
|
58
|
+
* This will also be used to migrate the database. If the fields are dynamic from the plugins
|
|
59
|
+
* configuration each time the configuration is changed a new migration will be created.
|
|
60
|
+
*
|
|
61
|
+
* NOTE: If you want to create migrations manually using
|
|
62
|
+
* migrations option or any other way you
|
|
63
|
+
* can disable migration per table basis.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* schema: {
|
|
68
|
+
* user: {
|
|
69
|
+
* fields: {
|
|
70
|
+
* email: {
|
|
71
|
+
* type: "string",
|
|
72
|
+
* },
|
|
73
|
+
* emailVerified: {
|
|
74
|
+
* type: "boolean",
|
|
75
|
+
* defaultValue: false,
|
|
76
|
+
* },
|
|
77
|
+
* },
|
|
78
|
+
* }
|
|
79
|
+
* } as AuthPluginSchema
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
schema?: BetterAuthPluginDBSchema | undefined;
|
|
83
|
+
/**
|
|
84
|
+
* The migrations of the plugin. If you define schema that will automatically create
|
|
85
|
+
* migrations for you.
|
|
86
|
+
*
|
|
87
|
+
* ⚠️ Only uses this if you dont't want to use the schema option and you disabled migrations for
|
|
88
|
+
* the tables.
|
|
89
|
+
*/
|
|
90
|
+
migrations?: Record<string, Migration> | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* The options of the plugin
|
|
93
|
+
*/
|
|
94
|
+
options?: Record<string, any> | undefined;
|
|
95
|
+
/**
|
|
96
|
+
* types to be inferred
|
|
97
|
+
*/
|
|
98
|
+
$Infer?: Record<string, any> | undefined;
|
|
99
|
+
/**
|
|
100
|
+
* The rate limit rules to apply to specific paths.
|
|
101
|
+
*/
|
|
102
|
+
rateLimit?: {
|
|
103
|
+
window: number;
|
|
104
|
+
max: number;
|
|
105
|
+
pathMatcher: (path: string) => boolean;
|
|
106
|
+
}[] | undefined;
|
|
107
|
+
/**
|
|
108
|
+
* The error codes returned by the plugin
|
|
109
|
+
*/
|
|
110
|
+
$ERROR_CODES?: Record<string, {
|
|
111
|
+
code: string;
|
|
112
|
+
message: string;
|
|
113
|
+
}> | undefined;
|
|
114
|
+
/**
|
|
115
|
+
* All database operations that are performed by the plugin
|
|
116
|
+
*
|
|
117
|
+
* This will override the default database operations
|
|
118
|
+
*/
|
|
119
|
+
adapter?: {
|
|
120
|
+
[key: string]: (...args: any[]) => Awaitable<any>;
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
//#endregion
|
|
124
|
+
export { BetterAuthPlugin, HookEndpointContext };
|
|
125
|
+
//# sourceMappingURL=plugin.d.mts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { DBFieldAttribute } from "../db/type.mjs";
|
|
2
|
+
import "../db/index.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/utils/db.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Filters output data by removing fields with the `returned: false` attribute.
|
|
7
|
+
* This ensures sensitive fields are not exposed in API responses.
|
|
8
|
+
*/
|
|
9
|
+
declare function filterOutputFields<T extends Record<string, unknown> | null>(data: T, additionalFields: Record<string, DBFieldAttribute> | undefined): T;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { filterOutputFields };
|
|
12
|
+
//# sourceMappingURL=db.d.mts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/utils/db.ts
|
|
2
|
+
/**
|
|
3
|
+
* Filters output data by removing fields with the `returned: false` attribute.
|
|
4
|
+
* This ensures sensitive fields are not exposed in API responses.
|
|
5
|
+
*/
|
|
6
|
+
function filterOutputFields(data, additionalFields) {
|
|
7
|
+
if (!data || !additionalFields) return data;
|
|
8
|
+
const returnFiltered = Object.entries(additionalFields).filter(([, { returned }]) => returned === false).map(([key]) => key);
|
|
9
|
+
return Object.entries(structuredClone(data)).filter(([key]) => !returnFiltered.includes(key)).reduce((acc, [key, value]) => ({
|
|
10
|
+
...acc,
|
|
11
|
+
[key]: value
|
|
12
|
+
}), {});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
//#endregion
|
|
16
|
+
export { filterOutputFields };
|
|
17
|
+
//# sourceMappingURL=db.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.mjs","names":[],"sources":["../../src/utils/db.ts"],"sourcesContent":["import type { DBFieldAttribute } from \"../db\";\n\n/**\n * Filters output data by removing fields with the `returned: false` attribute.\n * This ensures sensitive fields are not exposed in API responses.\n */\nexport function filterOutputFields<T extends Record<string, unknown> | null>(\n\tdata: T,\n\tadditionalFields: Record<string, DBFieldAttribute> | undefined,\n): T {\n\tif (!data || !additionalFields) {\n\t\treturn data;\n\t}\n\tconst returnFiltered = Object.entries(additionalFields)\n\t\t.filter(([, { returned }]) => returned === false)\n\t\t.map(([key]) => key);\n\treturn Object.entries(structuredClone(data))\n\t\t.filter(([key]) => !returnFiltered.includes(key))\n\t\t.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {} as T);\n}\n"],"mappings":";;;;;AAMA,SAAgB,mBACf,MACA,kBACI;AACJ,KAAI,CAAC,QAAQ,CAAC,iBACb,QAAO;CAER,MAAM,iBAAiB,OAAO,QAAQ,iBAAiB,CACrD,QAAQ,GAAG,EAAE,gBAAgB,aAAa,MAAM,CAChD,KAAK,CAAC,SAAS,IAAI;AACrB,QAAO,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,QAAQ,CAAC,SAAS,CAAC,eAAe,SAAS,IAAI,CAAC,CAChD,QAAQ,KAAK,CAAC,KAAK,YAAY;EAAE,GAAG;GAAM,MAAM;EAAO,GAAG,EAAE,CAAM"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { InternalLogger } from "../env/logger.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/deprecate.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Wraps a function to log a deprecation warning at once.
|
|
6
|
+
*/
|
|
7
|
+
declare function deprecate<T extends (...args: any[]) => any>(fn: T, message: string, logger?: InternalLogger): T;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { deprecate };
|
|
10
|
+
//# sourceMappingURL=deprecate.d.mts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/utils/deprecate.ts
|
|
2
|
+
/**
|
|
3
|
+
* Wraps a function to log a deprecation warning at once.
|
|
4
|
+
*/
|
|
5
|
+
function deprecate(fn, message, logger) {
|
|
6
|
+
let warned = false;
|
|
7
|
+
return function(...args) {
|
|
8
|
+
if (!warned) {
|
|
9
|
+
(logger?.warn ?? console.warn)(`[Deprecation] ${message}`);
|
|
10
|
+
warned = true;
|
|
11
|
+
}
|
|
12
|
+
return fn.apply(this, args);
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
17
|
+
export { deprecate };
|
|
18
|
+
//# sourceMappingURL=deprecate.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deprecate.mjs","names":[],"sources":["../../src/utils/deprecate.ts"],"sourcesContent":["import type { InternalLogger } from \"../env\";\n\n/**\n * Wraps a function to log a deprecation warning at once.\n */\nexport function deprecate<T extends (...args: any[]) => any>(\n\tfn: T,\n\tmessage: string,\n\tlogger?: InternalLogger,\n): T {\n\tlet warned = false;\n\n\treturn function (this: any, ...args: Parameters<T>): ReturnType<T> {\n\t\tif (!warned) {\n\t\t\tconst warn = logger?.warn ?? console.warn;\n\t\t\twarn(`[Deprecation] ${message}`);\n\t\t\twarned = true;\n\t\t}\n\t\treturn fn.apply(this, args);\n\t} as T;\n}\n"],"mappings":";;;;AAKA,SAAgB,UACf,IACA,SACA,QACI;CACJ,IAAI,SAAS;AAEb,QAAO,SAAqB,GAAG,MAAoC;AAClE,MAAI,CAAC,QAAQ;AAEZ,IADa,QAAQ,QAAQ,QAAQ,MAChC,iBAAiB,UAAU;AAChC,YAAS;;AAEV,SAAO,GAAG,MAAM,MAAM,KAAK"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/utils/error-codes.d.ts
|
|
2
|
+
type UpperLetter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z";
|
|
3
|
+
type SpecialCharacter = "_";
|
|
4
|
+
type IsValidUpperSnakeCase<S extends string> = S extends `${infer F}${infer R}` ? F extends UpperLetter | SpecialCharacter ? IsValidUpperSnakeCase<R> : false : true;
|
|
5
|
+
type InvalidKeyError<K extends string> = `Invalid error code key: "${K}" - must only contain uppercase letters (A-Z) and underscores (_)`;
|
|
6
|
+
type ValidateErrorCodes<T> = { [K in keyof T]: K extends string ? IsValidUpperSnakeCase<K> extends false ? InvalidKeyError<K> : T[K] : T[K] };
|
|
7
|
+
declare function defineErrorCodes<const T extends Record<string, string>>(codes: ValidateErrorCodes<T>): { [K in keyof T]: {
|
|
8
|
+
code: K;
|
|
9
|
+
message: T[K];
|
|
10
|
+
} };
|
|
11
|
+
//#endregion
|
|
12
|
+
export { defineErrorCodes };
|
|
13
|
+
//# sourceMappingURL=error-codes.d.mts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/utils/error-codes.ts
|
|
2
|
+
function defineErrorCodes(codes) {
|
|
3
|
+
return Object.fromEntries(Object.entries(codes).map(([key, value]) => [key, {
|
|
4
|
+
code: key,
|
|
5
|
+
message: value,
|
|
6
|
+
toString: () => value
|
|
7
|
+
}]));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
export { defineErrorCodes };
|
|
12
|
+
//# sourceMappingURL=error-codes.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-codes.mjs","names":[],"sources":["../../src/utils/error-codes.ts"],"sourcesContent":["type UpperLetter =\n\t| \"A\"\n\t| \"B\"\n\t| \"C\"\n\t| \"D\"\n\t| \"E\"\n\t| \"F\"\n\t| \"G\"\n\t| \"H\"\n\t| \"I\"\n\t| \"J\"\n\t| \"K\"\n\t| \"L\"\n\t| \"M\"\n\t| \"N\"\n\t| \"O\"\n\t| \"P\"\n\t| \"Q\"\n\t| \"R\"\n\t| \"S\"\n\t| \"T\"\n\t| \"U\"\n\t| \"V\"\n\t| \"W\"\n\t| \"X\"\n\t| \"Y\"\n\t| \"Z\";\ntype SpecialCharacter = \"_\";\n\ntype IsValidUpperSnakeCase<S extends string> = S extends `${infer F}${infer R}`\n\t? F extends UpperLetter | SpecialCharacter\n\t\t? IsValidUpperSnakeCase<R>\n\t\t: false\n\t: true;\n\ntype InvalidKeyError<K extends string> =\n\t`Invalid error code key: \"${K}\" - must only contain uppercase letters (A-Z) and underscores (_)`;\n\ntype ValidateErrorCodes<T> = {\n\t[K in keyof T]: K extends string\n\t\t? IsValidUpperSnakeCase<K> extends false\n\t\t\t? InvalidKeyError<K>\n\t\t\t: T[K]\n\t\t: T[K];\n};\n\nexport function defineErrorCodes<const T extends Record<string, string>>(\n\tcodes: ValidateErrorCodes<T>,\n): {\n\t[K in keyof T]: {\n\t\tcode: K;\n\t\tmessage: T[K];\n\t};\n} {\n\treturn Object.fromEntries(\n\t\tObject.entries(codes).map(([key, value]) => [\n\t\t\tkey,\n\t\t\t{\n\t\t\t\tcode: key,\n\t\t\t\tmessage: value,\n\t\t\t\ttoString: () => value,\n\t\t\t},\n\t\t]),\n\t) as any;\n}\n"],"mappings":";AA8CA,SAAgB,iBACf,OAMC;AACD,QAAO,OAAO,YACb,OAAO,QAAQ,MAAM,CAAC,KAAK,CAAC,KAAK,WAAW,CAC3C,KACA;EACC,MAAM;EACN,SAAS;EACT,gBAAgB;EAChB,CACD,CAAC,CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createRandomStringGenerator } from "@better-auth/utils/random";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/id.ts
|
|
4
|
+
const generateId = (size) => {
|
|
5
|
+
return createRandomStringGenerator("a-z", "A-Z", "0-9")(size || 32);
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
//#endregion
|
|
9
|
+
export { generateId };
|
|
10
|
+
//# sourceMappingURL=id.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"id.mjs","names":[],"sources":["../../src/utils/id.ts"],"sourcesContent":["import { createRandomStringGenerator } from \"@better-auth/utils/random\";\n\nexport const generateId = (size?: number) => {\n\treturn createRandomStringGenerator(\"a-z\", \"A-Z\", \"0-9\")(size || 32);\n};\n"],"mappings":";;;AAEA,MAAa,cAAc,SAAkB;AAC5C,QAAO,4BAA4B,OAAO,OAAO,MAAM,CAAC,QAAQ,GAAG"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
//#region src/utils/ip.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Normalizes an IP address for consistent rate limiting.
|
|
4
|
+
*
|
|
5
|
+
* Features:
|
|
6
|
+
* - Normalizes IPv6 to canonical lowercase form
|
|
7
|
+
* - Converts IPv4-mapped IPv6 to IPv4
|
|
8
|
+
* - Supports IPv6 subnet extraction
|
|
9
|
+
* - Handles all edge cases (::1, ::, etc.)
|
|
10
|
+
*/
|
|
11
|
+
interface NormalizeIPOptions {
|
|
12
|
+
/**
|
|
13
|
+
* For IPv6 addresses, extract the subnet prefix instead of full address.
|
|
14
|
+
* Common values: 32, 48, 64, 128 (default: 128 = full address)
|
|
15
|
+
*
|
|
16
|
+
* @default 128
|
|
17
|
+
*/
|
|
18
|
+
ipv6Subnet?: 128 | 64 | 48 | 32;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Checks if an IP is valid IPv4 or IPv6
|
|
22
|
+
*/
|
|
23
|
+
declare function isValidIP(ip: string): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Normalizes an IP address (IPv4 or IPv6) for consistent rate limiting.
|
|
26
|
+
*
|
|
27
|
+
* @param ip - The IP address to normalize
|
|
28
|
+
* @param options - Normalization options
|
|
29
|
+
* @returns Normalized IP address
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* normalizeIP("2001:DB8::1")
|
|
33
|
+
* // -> "2001:0db8:0000:0000:0000:0000:0000:0000"
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* normalizeIP("::ffff:192.0.2.1")
|
|
37
|
+
* // -> "192.0.2.1" (converted to IPv4)
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* normalizeIP("2001:db8::1", { ipv6Subnet: 64 })
|
|
41
|
+
* // -> "2001:0db8:0000:0000:0000:0000:0000:0000" (subnet /64)
|
|
42
|
+
*/
|
|
43
|
+
declare function normalizeIP(ip: string, options?: NormalizeIPOptions): string;
|
|
44
|
+
/**
|
|
45
|
+
* Creates a rate limit key from IP and path
|
|
46
|
+
* Uses a separator to prevent collision attacks
|
|
47
|
+
*
|
|
48
|
+
* @param ip - The IP address (should be normalized)
|
|
49
|
+
* @param path - The request path
|
|
50
|
+
* @returns Rate limit key
|
|
51
|
+
*/
|
|
52
|
+
declare function createRateLimitKey(ip: string, path: string): string;
|
|
53
|
+
//#endregion
|
|
54
|
+
export { createRateLimitKey, isValidIP, normalizeIP };
|
|
55
|
+
//# sourceMappingURL=ip.d.mts.map
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/ip.ts
|
|
4
|
+
/**
|
|
5
|
+
* Checks if an IP is valid IPv4 or IPv6
|
|
6
|
+
*/
|
|
7
|
+
function isValidIP(ip) {
|
|
8
|
+
return z.ipv4().safeParse(ip).success || z.ipv6().safeParse(ip).success;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Checks if an IP is IPv6
|
|
12
|
+
*/
|
|
13
|
+
function isIPv6(ip) {
|
|
14
|
+
return z.ipv6().safeParse(ip).success;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Converts IPv4-mapped IPv6 address to IPv4
|
|
18
|
+
* e.g., "::ffff:192.0.2.1" -> "192.0.2.1"
|
|
19
|
+
*/
|
|
20
|
+
function extractIPv4FromMapped(ipv6) {
|
|
21
|
+
const lower = ipv6.toLowerCase();
|
|
22
|
+
if (lower.startsWith("::ffff:")) {
|
|
23
|
+
const ipv4Part = lower.substring(7);
|
|
24
|
+
if (z.ipv4().safeParse(ipv4Part).success) return ipv4Part;
|
|
25
|
+
}
|
|
26
|
+
const parts = ipv6.split(":");
|
|
27
|
+
if (parts.length === 7 && parts[5]?.toLowerCase() === "ffff") {
|
|
28
|
+
const ipv4Part = parts[6];
|
|
29
|
+
if (ipv4Part && z.ipv4().safeParse(ipv4Part).success) return ipv4Part;
|
|
30
|
+
}
|
|
31
|
+
if (lower.includes("::ffff:") || lower.includes(":ffff:")) {
|
|
32
|
+
const groups = expandIPv6(ipv6);
|
|
33
|
+
if (groups.length === 8 && groups[0] === "0000" && groups[1] === "0000" && groups[2] === "0000" && groups[3] === "0000" && groups[4] === "0000" && groups[5] === "ffff" && groups[6] && groups[7]) return `${Number.parseInt(groups[6].substring(0, 2), 16)}.${Number.parseInt(groups[6].substring(2, 4), 16)}.${Number.parseInt(groups[7].substring(0, 2), 16)}.${Number.parseInt(groups[7].substring(2, 4), 16)}`;
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Expands a compressed IPv6 address to full form
|
|
39
|
+
* e.g., "2001:db8::1" -> ["2001", "0db8", "0000", "0000", "0000", "0000", "0000", "0001"]
|
|
40
|
+
*/
|
|
41
|
+
function expandIPv6(ipv6) {
|
|
42
|
+
if (ipv6.includes("::")) {
|
|
43
|
+
const sides = ipv6.split("::");
|
|
44
|
+
const left = sides[0] ? sides[0].split(":") : [];
|
|
45
|
+
const right = sides[1] ? sides[1].split(":") : [];
|
|
46
|
+
const missingGroups = 8 - left.length - right.length;
|
|
47
|
+
const zeros = Array(missingGroups).fill("0000");
|
|
48
|
+
const paddedLeft = left.map((g) => g.padStart(4, "0"));
|
|
49
|
+
const paddedRight = right.map((g) => g.padStart(4, "0"));
|
|
50
|
+
return [
|
|
51
|
+
...paddedLeft,
|
|
52
|
+
...zeros,
|
|
53
|
+
...paddedRight
|
|
54
|
+
];
|
|
55
|
+
}
|
|
56
|
+
return ipv6.split(":").map((g) => g.padStart(4, "0"));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Normalizes an IPv6 address to canonical form
|
|
60
|
+
* e.g., "2001:DB8::1" -> "2001:0db8:0000:0000:0000:0000:0000:0001"
|
|
61
|
+
*/
|
|
62
|
+
function normalizeIPv6(ipv6, subnetPrefix) {
|
|
63
|
+
const groups = expandIPv6(ipv6);
|
|
64
|
+
if (subnetPrefix && subnetPrefix < 128) {
|
|
65
|
+
let bitsRemaining = subnetPrefix;
|
|
66
|
+
return groups.map((group) => {
|
|
67
|
+
if (bitsRemaining <= 0) return "0000";
|
|
68
|
+
if (bitsRemaining >= 16) {
|
|
69
|
+
bitsRemaining -= 16;
|
|
70
|
+
return group;
|
|
71
|
+
}
|
|
72
|
+
const masked = Number.parseInt(group, 16) & (65535 << 16 - bitsRemaining & 65535);
|
|
73
|
+
bitsRemaining = 0;
|
|
74
|
+
return masked.toString(16).padStart(4, "0");
|
|
75
|
+
}).join(":").toLowerCase();
|
|
76
|
+
}
|
|
77
|
+
return groups.join(":").toLowerCase();
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Normalizes an IP address (IPv4 or IPv6) for consistent rate limiting.
|
|
81
|
+
*
|
|
82
|
+
* @param ip - The IP address to normalize
|
|
83
|
+
* @param options - Normalization options
|
|
84
|
+
* @returns Normalized IP address
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* normalizeIP("2001:DB8::1")
|
|
88
|
+
* // -> "2001:0db8:0000:0000:0000:0000:0000:0000"
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* normalizeIP("::ffff:192.0.2.1")
|
|
92
|
+
* // -> "192.0.2.1" (converted to IPv4)
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* normalizeIP("2001:db8::1", { ipv6Subnet: 64 })
|
|
96
|
+
* // -> "2001:0db8:0000:0000:0000:0000:0000:0000" (subnet /64)
|
|
97
|
+
*/
|
|
98
|
+
function normalizeIP(ip, options = {}) {
|
|
99
|
+
if (z.ipv4().safeParse(ip).success) return ip.toLowerCase();
|
|
100
|
+
if (!isIPv6(ip)) return ip.toLowerCase();
|
|
101
|
+
const ipv4 = extractIPv4FromMapped(ip);
|
|
102
|
+
if (ipv4) return ipv4.toLowerCase();
|
|
103
|
+
return normalizeIPv6(ip, options.ipv6Subnet || 64);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Creates a rate limit key from IP and path
|
|
107
|
+
* Uses a separator to prevent collision attacks
|
|
108
|
+
*
|
|
109
|
+
* @param ip - The IP address (should be normalized)
|
|
110
|
+
* @param path - The request path
|
|
111
|
+
* @returns Rate limit key
|
|
112
|
+
*/
|
|
113
|
+
function createRateLimitKey(ip, path) {
|
|
114
|
+
return `${ip}|${path}`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
//#endregion
|
|
118
|
+
export { createRateLimitKey, isValidIP, normalizeIP };
|
|
119
|
+
//# sourceMappingURL=ip.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ip.mjs","names":[],"sources":["../../src/utils/ip.ts"],"sourcesContent":["import * as z from \"zod\";\n\n/**\n * Normalizes an IP address for consistent rate limiting.\n *\n * Features:\n * - Normalizes IPv6 to canonical lowercase form\n * - Converts IPv4-mapped IPv6 to IPv4\n * - Supports IPv6 subnet extraction\n * - Handles all edge cases (::1, ::, etc.)\n */\n\ninterface NormalizeIPOptions {\n\t/**\n\t * For IPv6 addresses, extract the subnet prefix instead of full address.\n\t * Common values: 32, 48, 64, 128 (default: 128 = full address)\n\t *\n\t * @default 128\n\t */\n\tipv6Subnet?: 128 | 64 | 48 | 32;\n}\n\n/**\n * Checks if an IP is valid IPv4 or IPv6\n */\nexport function isValidIP(ip: string): boolean {\n\treturn z.ipv4().safeParse(ip).success || z.ipv6().safeParse(ip).success;\n}\n\n/**\n * Checks if an IP is IPv6\n */\nfunction isIPv6(ip: string): boolean {\n\treturn z.ipv6().safeParse(ip).success;\n}\n\n/**\n * Converts IPv4-mapped IPv6 address to IPv4\n * e.g., \"::ffff:192.0.2.1\" -> \"192.0.2.1\"\n */\nfunction extractIPv4FromMapped(ipv6: string): string | null {\n\tconst lower = ipv6.toLowerCase();\n\n\t// Handle ::ffff:192.0.2.1 format\n\tif (lower.startsWith(\"::ffff:\")) {\n\t\tconst ipv4Part = lower.substring(7);\n\t\t// Check if it's a valid IPv4\n\t\tif (z.ipv4().safeParse(ipv4Part).success) {\n\t\t\treturn ipv4Part;\n\t\t}\n\t}\n\n\t// Handle full form: 0:0:0:0:0:ffff:192.0.2.1\n\tconst parts = ipv6.split(\":\");\n\tif (parts.length === 7 && parts[5]?.toLowerCase() === \"ffff\") {\n\t\tconst ipv4Part = parts[6];\n\t\tif (ipv4Part && z.ipv4().safeParse(ipv4Part).success) {\n\t\t\treturn ipv4Part;\n\t\t}\n\t}\n\n\t// Handle hex-encoded IPv4 in mapped address\n\t// e.g., ::ffff:c000:0201 -> 192.0.2.1\n\tif (lower.includes(\"::ffff:\") || lower.includes(\":ffff:\")) {\n\t\tconst groups = expandIPv6(ipv6);\n\t\tif (\n\t\t\tgroups.length === 8 &&\n\t\t\tgroups[0] === \"0000\" &&\n\t\t\tgroups[1] === \"0000\" &&\n\t\t\tgroups[2] === \"0000\" &&\n\t\t\tgroups[3] === \"0000\" &&\n\t\t\tgroups[4] === \"0000\" &&\n\t\t\tgroups[5] === \"ffff\" &&\n\t\t\tgroups[6] &&\n\t\t\tgroups[7]\n\t\t) {\n\t\t\t// Convert last two groups to IPv4\n\t\t\tconst byte1 = Number.parseInt(groups[6].substring(0, 2), 16);\n\t\t\tconst byte2 = Number.parseInt(groups[6].substring(2, 4), 16);\n\t\t\tconst byte3 = Number.parseInt(groups[7].substring(0, 2), 16);\n\t\t\tconst byte4 = Number.parseInt(groups[7].substring(2, 4), 16);\n\t\t\treturn `${byte1}.${byte2}.${byte3}.${byte4}`;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Expands a compressed IPv6 address to full form\n * e.g., \"2001:db8::1\" -> [\"2001\", \"0db8\", \"0000\", \"0000\", \"0000\", \"0000\", \"0000\", \"0001\"]\n */\nfunction expandIPv6(ipv6: string): string[] {\n\t// Handle :: notation (zero compression)\n\tif (ipv6.includes(\"::\")) {\n\t\tconst sides = ipv6.split(\"::\");\n\t\tconst left = sides[0] ? sides[0].split(\":\") : [];\n\t\tconst right = sides[1] ? sides[1].split(\":\") : [];\n\n\t\t// Calculate missing groups\n\t\tconst totalGroups = 8;\n\t\tconst missingGroups = totalGroups - left.length - right.length;\n\t\tconst zeros = Array(missingGroups).fill(\"0000\");\n\n\t\t// Pad existing groups to 4 digits\n\t\tconst paddedLeft = left.map((g) => g.padStart(4, \"0\"));\n\t\tconst paddedRight = right.map((g) => g.padStart(4, \"0\"));\n\n\t\treturn [...paddedLeft, ...zeros, ...paddedRight];\n\t}\n\n\t// No compression, just pad each group\n\treturn ipv6.split(\":\").map((g) => g.padStart(4, \"0\"));\n}\n\n/**\n * Normalizes an IPv6 address to canonical form\n * e.g., \"2001:DB8::1\" -> \"2001:0db8:0000:0000:0000:0000:0000:0001\"\n */\nfunction normalizeIPv6(\n\tipv6: string,\n\tsubnetPrefix?: 128 | 32 | 48 | 64,\n): string {\n\tconst groups = expandIPv6(ipv6);\n\n\tif (subnetPrefix && subnetPrefix < 128) {\n\t\t// Apply subnet mask\n\t\tconst prefix = subnetPrefix;\n\t\tlet bitsRemaining: number = prefix;\n\n\t\tconst maskedGroups = groups.map((group) => {\n\t\t\tif (bitsRemaining <= 0) {\n\t\t\t\treturn \"0000\";\n\t\t\t}\n\t\t\tif (bitsRemaining >= 16) {\n\t\t\t\tbitsRemaining -= 16;\n\t\t\t\treturn group;\n\t\t\t}\n\n\t\t\t// Partial mask for this group\n\t\t\tconst value = Number.parseInt(group, 16);\n\t\t\tconst mask = (0xffff << (16 - bitsRemaining)) & 0xffff;\n\t\t\tconst masked = value & mask;\n\t\t\tbitsRemaining = 0;\n\t\t\treturn masked.toString(16).padStart(4, \"0\");\n\t\t});\n\n\t\treturn maskedGroups.join(\":\").toLowerCase();\n\t}\n\n\treturn groups.join(\":\").toLowerCase();\n}\n\n/**\n * Normalizes an IP address (IPv4 or IPv6) for consistent rate limiting.\n *\n * @param ip - The IP address to normalize\n * @param options - Normalization options\n * @returns Normalized IP address\n *\n * @example\n * normalizeIP(\"2001:DB8::1\")\n * // -> \"2001:0db8:0000:0000:0000:0000:0000:0000\"\n *\n * @example\n * normalizeIP(\"::ffff:192.0.2.1\")\n * // -> \"192.0.2.1\" (converted to IPv4)\n *\n * @example\n * normalizeIP(\"2001:db8::1\", { ipv6Subnet: 64 })\n * // -> \"2001:0db8:0000:0000:0000:0000:0000:0000\" (subnet /64)\n */\nexport function normalizeIP(\n\tip: string,\n\toptions: NormalizeIPOptions = {},\n): string {\n\t// IPv4 addresses are already normalized\n\tif (z.ipv4().safeParse(ip).success) {\n\t\treturn ip.toLowerCase();\n\t}\n\n\t// Check if it's IPv6\n\tif (!isIPv6(ip)) {\n\t\t// Return as-is if not valid (shouldn't happen due to prior validation)\n\t\treturn ip.toLowerCase();\n\t}\n\n\t// Check for IPv4-mapped IPv6\n\tconst ipv4 = extractIPv4FromMapped(ip);\n\tif (ipv4) {\n\t\treturn ipv4.toLowerCase();\n\t}\n\n\t// Normalize IPv6\n\tconst subnetPrefix = options.ipv6Subnet || 64;\n\treturn normalizeIPv6(ip, subnetPrefix);\n}\n\n/**\n * Creates a rate limit key from IP and path\n * Uses a separator to prevent collision attacks\n *\n * @param ip - The IP address (should be normalized)\n * @param path - The request path\n * @returns Rate limit key\n */\nexport function createRateLimitKey(ip: string, path: string): string {\n\t// Use | as separator to prevent collision attacks\n\t// e.g., \"192.0.2.1\" + \"/sign-in\" vs \"192.0.2\" + \".1/sign-in\"\n\treturn `${ip}|${path}`;\n}\n"],"mappings":";;;;;;AAyBA,SAAgB,UAAU,IAAqB;AAC9C,QAAO,EAAE,MAAM,CAAC,UAAU,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,UAAU,GAAG,CAAC;;;;;AAMjE,SAAS,OAAO,IAAqB;AACpC,QAAO,EAAE,MAAM,CAAC,UAAU,GAAG,CAAC;;;;;;AAO/B,SAAS,sBAAsB,MAA6B;CAC3D,MAAM,QAAQ,KAAK,aAAa;AAGhC,KAAI,MAAM,WAAW,UAAU,EAAE;EAChC,MAAM,WAAW,MAAM,UAAU,EAAE;AAEnC,MAAI,EAAE,MAAM,CAAC,UAAU,SAAS,CAAC,QAChC,QAAO;;CAKT,MAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,KAAI,MAAM,WAAW,KAAK,MAAM,IAAI,aAAa,KAAK,QAAQ;EAC7D,MAAM,WAAW,MAAM;AACvB,MAAI,YAAY,EAAE,MAAM,CAAC,UAAU,SAAS,CAAC,QAC5C,QAAO;;AAMT,KAAI,MAAM,SAAS,UAAU,IAAI,MAAM,SAAS,SAAS,EAAE;EAC1D,MAAM,SAAS,WAAW,KAAK;AAC/B,MACC,OAAO,WAAW,KAClB,OAAO,OAAO,UACd,OAAO,OAAO,UACd,OAAO,OAAO,UACd,OAAO,OAAO,UACd,OAAO,OAAO,UACd,OAAO,OAAO,UACd,OAAO,MACP,OAAO,GAOP,QAAO,GAJO,OAAO,SAAS,OAAO,GAAG,UAAU,GAAG,EAAE,EAAE,GAAG,CAI5C,GAHF,OAAO,SAAS,OAAO,GAAG,UAAU,GAAG,EAAE,EAAE,GAAG,CAGnC,GAFX,OAAO,SAAS,OAAO,GAAG,UAAU,GAAG,EAAE,EAAE,GAAG,CAE1B,GADpB,OAAO,SAAS,OAAO,GAAG,UAAU,GAAG,EAAE,EAAE,GAAG;;AAK9D,QAAO;;;;;;AAOR,SAAS,WAAW,MAAwB;AAE3C,KAAI,KAAK,SAAS,KAAK,EAAE;EACxB,MAAM,QAAQ,KAAK,MAAM,KAAK;EAC9B,MAAM,OAAO,MAAM,KAAK,MAAM,GAAG,MAAM,IAAI,GAAG,EAAE;EAChD,MAAM,QAAQ,MAAM,KAAK,MAAM,GAAG,MAAM,IAAI,GAAG,EAAE;EAIjD,MAAM,gBADc,IACgB,KAAK,SAAS,MAAM;EACxD,MAAM,QAAQ,MAAM,cAAc,CAAC,KAAK,OAAO;EAG/C,MAAM,aAAa,KAAK,KAAK,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;EACtD,MAAM,cAAc,MAAM,KAAK,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;AAExD,SAAO;GAAC,GAAG;GAAY,GAAG;GAAO,GAAG;GAAY;;AAIjD,QAAO,KAAK,MAAM,IAAI,CAAC,KAAK,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;;;;;;AAOtD,SAAS,cACR,MACA,cACS;CACT,MAAM,SAAS,WAAW,KAAK;AAE/B,KAAI,gBAAgB,eAAe,KAAK;EAGvC,IAAI,gBADW;AAoBf,SAjBqB,OAAO,KAAK,UAAU;AAC1C,OAAI,iBAAiB,EACpB,QAAO;AAER,OAAI,iBAAiB,IAAI;AACxB,qBAAiB;AACjB,WAAO;;GAMR,MAAM,SAFQ,OAAO,SAAS,OAAO,GAAG,IAC1B,SAAW,KAAK,gBAAkB;AAEhD,mBAAgB;AAChB,UAAO,OAAO,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI;IAC1C,CAEkB,KAAK,IAAI,CAAC,aAAa;;AAG5C,QAAO,OAAO,KAAK,IAAI,CAAC,aAAa;;;;;;;;;;;;;;;;;;;;;AAsBtC,SAAgB,YACf,IACA,UAA8B,EAAE,EACvB;AAET,KAAI,EAAE,MAAM,CAAC,UAAU,GAAG,CAAC,QAC1B,QAAO,GAAG,aAAa;AAIxB,KAAI,CAAC,OAAO,GAAG,CAEd,QAAO,GAAG,aAAa;CAIxB,MAAM,OAAO,sBAAsB,GAAG;AACtC,KAAI,KACH,QAAO,KAAK,aAAa;AAK1B,QAAO,cAAc,IADA,QAAQ,cAAc,GACL;;;;;;;;;;AAWvC,SAAgB,mBAAmB,IAAY,MAAsB;AAGpE,QAAO,GAAG,GAAG,GAAG"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { logger } from "../env/logger.mjs";
|
|
2
|
+
import "../env/index.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/utils/json.ts
|
|
5
|
+
function safeJSONParse(data) {
|
|
6
|
+
function reviver(_, value) {
|
|
7
|
+
if (typeof value === "string") {
|
|
8
|
+
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/.test(value)) {
|
|
9
|
+
const date = new Date(value);
|
|
10
|
+
if (!isNaN(date.getTime())) return date;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
if (typeof data !== "string") return data;
|
|
17
|
+
return JSON.parse(data, reviver);
|
|
18
|
+
} catch (e) {
|
|
19
|
+
logger.error("Error parsing JSON", { error: e });
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
export { safeJSONParse };
|
|
26
|
+
//# sourceMappingURL=json.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.mjs","names":[],"sources":["../../src/utils/json.ts"],"sourcesContent":["import { logger } from \"../env\";\n\nexport function safeJSONParse<T>(data: unknown): T | null {\n\tfunction reviver(_: string, value: any): any {\n\t\tif (typeof value === \"string\") {\n\t\t\tconst iso8601Regex = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?Z$/;\n\t\t\tif (iso8601Regex.test(value)) {\n\t\t\t\tconst date = new Date(value);\n\t\t\t\tif (!isNaN(date.getTime())) {\n\t\t\t\t\treturn date;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn value;\n\t}\n\ttry {\n\t\tif (typeof data !== \"string\") {\n\t\t\treturn data as T;\n\t\t}\n\t\treturn JSON.parse(data, reviver);\n\t} catch (e) {\n\t\tlogger.error(\"Error parsing JSON\", { error: e });\n\t\treturn null;\n\t}\n}\n"],"mappings":";;;;AAEA,SAAgB,cAAiB,MAAyB;CACzD,SAAS,QAAQ,GAAW,OAAiB;AAC5C,MAAI,OAAO,UAAU,UAEpB;OADqB,mDACJ,KAAK,MAAM,EAAE;IAC7B,MAAM,OAAO,IAAI,KAAK,MAAM;AAC5B,QAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CACzB,QAAO;;;AAIV,SAAO;;AAER,KAAI;AACH,MAAI,OAAO,SAAS,SACnB,QAAO;AAER,SAAO,KAAK,MAAM,MAAM,QAAQ;UACxB,GAAG;AACX,SAAO,MAAM,sBAAsB,EAAE,OAAO,GAAG,CAAC;AAChD,SAAO"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"string.mjs","names":[],"sources":["../../src/utils/string.ts"],"sourcesContent":["export function capitalizeFirstLetter(str: string) {\n\treturn str.charAt(0).toUpperCase() + str.slice(1);\n}\n"],"mappings":";AAAA,SAAgB,sBAAsB,KAAa;AAClD,QAAO,IAAI,OAAO,EAAE,CAAC,aAAa,GAAG,IAAI,MAAM,EAAE"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/utils/url.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Normalizes a request pathname by removing the basePath prefix and trailing slashes.
|
|
4
|
+
* This is useful for matching paths against configured path lists.
|
|
5
|
+
*
|
|
6
|
+
* @param requestUrl - The full request URL
|
|
7
|
+
* @param basePath - The base path of the auth API (e.g., "/api/auth")
|
|
8
|
+
* @returns The normalized path without basePath prefix or trailing slashes,
|
|
9
|
+
* or "/" if URL parsing fails
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* normalizePathname("http://localhost:3000/api/auth/sso/saml2/callback/provider1", "/api/auth")
|
|
13
|
+
* // Returns: "/sso/saml2/callback/provider1"
|
|
14
|
+
*
|
|
15
|
+
* normalizePathname("http://localhost:3000/sso/saml2/callback/provider1/", "/")
|
|
16
|
+
* // Returns: "/sso/saml2/callback/provider1"
|
|
17
|
+
*/
|
|
18
|
+
declare function normalizePathname(requestUrl: string, basePath: string): string;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { normalizePathname };
|
|
21
|
+
//# sourceMappingURL=url.d.mts.map
|