@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.
Files changed (353) hide show
  1. package/.turbo/turbo-build.log +266 -0
  2. package/.turbo/turbo-test.log +2 -0
  3. package/LICENSE.md +20 -0
  4. package/dist/api/index.d.mts +181 -0
  5. package/dist/api/index.mjs +34 -0
  6. package/dist/api/index.mjs.map +1 -0
  7. package/dist/async_hooks/index.d.mts +7 -0
  8. package/dist/async_hooks/index.mjs +22 -0
  9. package/dist/async_hooks/index.mjs.map +1 -0
  10. package/dist/async_hooks/pure.index.d.mts +7 -0
  11. package/dist/async_hooks/pure.index.mjs +35 -0
  12. package/dist/async_hooks/pure.index.mjs.map +1 -0
  13. package/dist/context/endpoint-context.d.mts +19 -0
  14. package/dist/context/endpoint-context.mjs +32 -0
  15. package/dist/context/endpoint-context.mjs.map +1 -0
  16. package/dist/context/global.d.mts +7 -0
  17. package/dist/context/global.mjs +38 -0
  18. package/dist/context/global.mjs.map +1 -0
  19. package/dist/context/index.d.mts +5 -0
  20. package/dist/context/index.mjs +6 -0
  21. package/dist/context/request-state.d.mts +26 -0
  22. package/dist/context/request-state.mjs +50 -0
  23. package/dist/context/request-state.mjs.map +1 -0
  24. package/dist/context/transaction.d.mts +25 -0
  25. package/dist/context/transaction.mjs +96 -0
  26. package/dist/context/transaction.mjs.map +1 -0
  27. package/dist/db/adapter/factory.d.mts +28 -0
  28. package/dist/db/adapter/factory.mjs +716 -0
  29. package/dist/db/adapter/factory.mjs.map +1 -0
  30. package/dist/db/adapter/get-default-field-name.d.mts +19 -0
  31. package/dist/db/adapter/get-default-field-name.mjs +39 -0
  32. package/dist/db/adapter/get-default-field-name.mjs.map +1 -0
  33. package/dist/db/adapter/get-default-model-name.d.mts +13 -0
  34. package/dist/db/adapter/get-default-model-name.mjs +33 -0
  35. package/dist/db/adapter/get-default-model-name.mjs.map +1 -0
  36. package/dist/db/adapter/get-field-attributes.d.mts +30 -0
  37. package/dist/db/adapter/get-field-attributes.mjs +40 -0
  38. package/dist/db/adapter/get-field-attributes.mjs.map +1 -0
  39. package/dist/db/adapter/get-field-name.d.mts +19 -0
  40. package/dist/db/adapter/get-field-name.mjs +34 -0
  41. package/dist/db/adapter/get-field-name.mjs.map +1 -0
  42. package/dist/db/adapter/get-id-field.d.mts +40 -0
  43. package/dist/db/adapter/get-id-field.mjs +68 -0
  44. package/dist/db/adapter/get-id-field.mjs.map +1 -0
  45. package/dist/db/adapter/get-model-name.d.mts +13 -0
  46. package/dist/db/adapter/get-model-name.mjs +24 -0
  47. package/dist/db/adapter/get-model-name.mjs.map +1 -0
  48. package/dist/db/adapter/index.d.mts +515 -0
  49. package/dist/db/adapter/index.mjs +10 -0
  50. package/dist/db/adapter/types.d.mts +140 -0
  51. package/dist/db/adapter/utils.d.mts +8 -0
  52. package/dist/db/adapter/utils.mjs +39 -0
  53. package/dist/db/adapter/utils.mjs.map +1 -0
  54. package/dist/db/get-tables.d.mts +9 -0
  55. package/dist/db/get-tables.mjs +267 -0
  56. package/dist/db/get-tables.mjs.map +1 -0
  57. package/dist/db/index.d.mts +10 -0
  58. package/dist/db/index.mjs +9 -0
  59. package/dist/db/plugin.d.mts +13 -0
  60. package/dist/db/schema/account.d.mts +27 -0
  61. package/dist/db/schema/account.mjs +20 -0
  62. package/dist/db/schema/account.mjs.map +1 -0
  63. package/dist/db/schema/rate-limit.d.mts +15 -0
  64. package/dist/db/schema/rate-limit.mjs +12 -0
  65. package/dist/db/schema/rate-limit.mjs.map +1 -0
  66. package/dist/db/schema/session.d.mts +22 -0
  67. package/dist/db/schema/session.mjs +15 -0
  68. package/dist/db/schema/session.mjs.map +1 -0
  69. package/dist/db/schema/shared.d.mts +11 -0
  70. package/dist/db/schema/shared.mjs +12 -0
  71. package/dist/db/schema/shared.mjs.map +1 -0
  72. package/dist/db/schema/user.d.mts +21 -0
  73. package/dist/db/schema/user.mjs +14 -0
  74. package/dist/db/schema/user.mjs.map +1 -0
  75. package/dist/db/schema/verification.d.mts +20 -0
  76. package/dist/db/schema/verification.mjs +13 -0
  77. package/dist/db/schema/verification.mjs.map +1 -0
  78. package/dist/db/type.d.mts +147 -0
  79. package/dist/env/color-depth.d.mts +5 -0
  80. package/dist/env/color-depth.mjs +89 -0
  81. package/dist/env/color-depth.mjs.map +1 -0
  82. package/dist/env/env-impl.d.mts +33 -0
  83. package/dist/env/env-impl.mjs +83 -0
  84. package/dist/env/env-impl.mjs.map +1 -0
  85. package/dist/env/index.d.mts +4 -0
  86. package/dist/env/index.mjs +5 -0
  87. package/dist/env/logger.d.mts +49 -0
  88. package/dist/env/logger.mjs +82 -0
  89. package/dist/env/logger.mjs.map +1 -0
  90. package/dist/error/codes.d.mts +199 -0
  91. package/dist/error/codes.mjs +57 -0
  92. package/dist/error/codes.mjs.map +1 -0
  93. package/dist/error/index.d.mts +20 -0
  94. package/dist/error/index.mjs +30 -0
  95. package/dist/error/index.mjs.map +1 -0
  96. package/dist/index.d.mts +8 -0
  97. package/dist/index.mjs +1 -0
  98. package/dist/oauth2/client-credentials-token.d.mts +37 -0
  99. package/dist/oauth2/client-credentials-token.mjs +55 -0
  100. package/dist/oauth2/client-credentials-token.mjs.map +1 -0
  101. package/dist/oauth2/create-authorization-url.d.mts +46 -0
  102. package/dist/oauth2/create-authorization-url.mjs +43 -0
  103. package/dist/oauth2/create-authorization-url.mjs.map +1 -0
  104. package/dist/oauth2/index.d.mts +8 -0
  105. package/dist/oauth2/index.mjs +8 -0
  106. package/dist/oauth2/oauth-provider.d.mts +195 -0
  107. package/dist/oauth2/refresh-access-token.d.mts +36 -0
  108. package/dist/oauth2/refresh-access-token.mjs +59 -0
  109. package/dist/oauth2/refresh-access-token.mjs.map +1 -0
  110. package/dist/oauth2/utils.d.mts +8 -0
  111. package/dist/oauth2/utils.mjs +28 -0
  112. package/dist/oauth2/utils.mjs.map +1 -0
  113. package/dist/oauth2/validate-authorization-code.d.mts +56 -0
  114. package/dist/oauth2/validate-authorization-code.mjs +72 -0
  115. package/dist/oauth2/validate-authorization-code.mjs.map +1 -0
  116. package/dist/oauth2/verify.d.mts +43 -0
  117. package/dist/oauth2/verify.mjs +96 -0
  118. package/dist/oauth2/verify.mjs.map +1 -0
  119. package/dist/social-providers/apple.d.mts +120 -0
  120. package/dist/social-providers/apple.mjs +105 -0
  121. package/dist/social-providers/apple.mjs.map +1 -0
  122. package/dist/social-providers/atlassian.d.mts +73 -0
  123. package/dist/social-providers/atlassian.mjs +84 -0
  124. package/dist/social-providers/atlassian.mjs.map +1 -0
  125. package/dist/social-providers/cognito.d.mts +88 -0
  126. package/dist/social-providers/cognito.mjs +166 -0
  127. package/dist/social-providers/cognito.mjs.map +1 -0
  128. package/dist/social-providers/discord.d.mts +127 -0
  129. package/dist/social-providers/discord.mjs +65 -0
  130. package/dist/social-providers/discord.mjs.map +1 -0
  131. package/dist/social-providers/dropbox.d.mts +72 -0
  132. package/dist/social-providers/dropbox.mjs +76 -0
  133. package/dist/social-providers/dropbox.mjs.map +1 -0
  134. package/dist/social-providers/facebook.d.mts +82 -0
  135. package/dist/social-providers/facebook.mjs +121 -0
  136. package/dist/social-providers/facebook.mjs.map +1 -0
  137. package/dist/social-providers/figma.d.mts +64 -0
  138. package/dist/social-providers/figma.mjs +87 -0
  139. package/dist/social-providers/figma.mjs.map +1 -0
  140. package/dist/social-providers/github.d.mts +105 -0
  141. package/dist/social-providers/github.mjs +97 -0
  142. package/dist/social-providers/github.mjs.map +1 -0
  143. package/dist/social-providers/gitlab.d.mts +126 -0
  144. package/dist/social-providers/gitlab.mjs +83 -0
  145. package/dist/social-providers/gitlab.mjs.map +1 -0
  146. package/dist/social-providers/google.d.mts +100 -0
  147. package/dist/social-providers/google.mjs +109 -0
  148. package/dist/social-providers/google.mjs.map +1 -0
  149. package/dist/social-providers/huggingface.d.mts +86 -0
  150. package/dist/social-providers/huggingface.mjs +76 -0
  151. package/dist/social-providers/huggingface.mjs.map +1 -0
  152. package/dist/social-providers/index.d.mts +1725 -0
  153. package/dist/social-providers/index.mjs +77 -0
  154. package/dist/social-providers/index.mjs.map +1 -0
  155. package/dist/social-providers/kakao.d.mts +164 -0
  156. package/dist/social-providers/kakao.mjs +73 -0
  157. package/dist/social-providers/kakao.mjs.map +1 -0
  158. package/dist/social-providers/kick.d.mts +76 -0
  159. package/dist/social-providers/kick.mjs +72 -0
  160. package/dist/social-providers/kick.mjs.map +1 -0
  161. package/dist/social-providers/line.d.mts +108 -0
  162. package/dist/social-providers/line.mjs +114 -0
  163. package/dist/social-providers/line.mjs.map +1 -0
  164. package/dist/social-providers/linear.d.mts +71 -0
  165. package/dist/social-providers/linear.mjs +89 -0
  166. package/dist/social-providers/linear.mjs.map +1 -0
  167. package/dist/social-providers/linkedin.d.mts +70 -0
  168. package/dist/social-providers/linkedin.mjs +77 -0
  169. package/dist/social-providers/linkedin.mjs.map +1 -0
  170. package/dist/social-providers/microsoft-entra-id.d.mts +175 -0
  171. package/dist/social-providers/microsoft-entra-id.mjs +107 -0
  172. package/dist/social-providers/microsoft-entra-id.mjs.map +1 -0
  173. package/dist/social-providers/naver.d.mts +95 -0
  174. package/dist/social-providers/naver.mjs +68 -0
  175. package/dist/social-providers/naver.mjs.map +1 -0
  176. package/dist/social-providers/notion.d.mts +67 -0
  177. package/dist/social-providers/notion.mjs +76 -0
  178. package/dist/social-providers/notion.mjs.map +1 -0
  179. package/dist/social-providers/paybin.d.mts +74 -0
  180. package/dist/social-providers/paybin.mjs +86 -0
  181. package/dist/social-providers/paybin.mjs.map +1 -0
  182. package/dist/social-providers/paypal.d.mts +132 -0
  183. package/dist/social-providers/paypal.mjs +145 -0
  184. package/dist/social-providers/paypal.mjs.map +1 -0
  185. package/dist/social-providers/polar.d.mts +77 -0
  186. package/dist/social-providers/polar.mjs +74 -0
  187. package/dist/social-providers/polar.mjs.map +1 -0
  188. package/dist/social-providers/reddit.d.mts +65 -0
  189. package/dist/social-providers/reddit.mjs +84 -0
  190. package/dist/social-providers/reddit.mjs.map +1 -0
  191. package/dist/social-providers/roblox.d.mts +73 -0
  192. package/dist/social-providers/roblox.mjs +60 -0
  193. package/dist/social-providers/roblox.mjs.map +1 -0
  194. package/dist/social-providers/salesforce.d.mts +82 -0
  195. package/dist/social-providers/salesforce.mjs +92 -0
  196. package/dist/social-providers/salesforce.mjs.map +1 -0
  197. package/dist/social-providers/slack.d.mts +86 -0
  198. package/dist/social-providers/slack.mjs +69 -0
  199. package/dist/social-providers/slack.mjs.map +1 -0
  200. package/dist/social-providers/spotify.d.mts +66 -0
  201. package/dist/social-providers/spotify.mjs +72 -0
  202. package/dist/social-providers/spotify.mjs.map +1 -0
  203. package/dist/social-providers/tiktok.d.mts +171 -0
  204. package/dist/social-providers/tiktok.mjs +63 -0
  205. package/dist/social-providers/tiktok.mjs.map +1 -0
  206. package/dist/social-providers/twitch.d.mts +82 -0
  207. package/dist/social-providers/twitch.mjs +79 -0
  208. package/dist/social-providers/twitch.mjs.map +1 -0
  209. package/dist/social-providers/twitter.d.mts +129 -0
  210. package/dist/social-providers/twitter.mjs +88 -0
  211. package/dist/social-providers/twitter.mjs.map +1 -0
  212. package/dist/social-providers/vercel.d.mts +65 -0
  213. package/dist/social-providers/vercel.mjs +62 -0
  214. package/dist/social-providers/vercel.mjs.map +1 -0
  215. package/dist/social-providers/vk.d.mts +73 -0
  216. package/dist/social-providers/vk.mjs +84 -0
  217. package/dist/social-providers/vk.mjs.map +1 -0
  218. package/dist/social-providers/zoom.d.mts +173 -0
  219. package/dist/social-providers/zoom.mjs +73 -0
  220. package/dist/social-providers/zoom.mjs.map +1 -0
  221. package/dist/types/context.d.mts +267 -0
  222. package/dist/types/cookie.d.mts +16 -0
  223. package/dist/types/helper.d.mts +10 -0
  224. package/dist/types/index.d.mts +8 -0
  225. package/dist/types/init-options.d.mts +1314 -0
  226. package/dist/types/plugin-client.d.mts +112 -0
  227. package/dist/types/plugin.d.mts +125 -0
  228. package/dist/utils/db.d.mts +12 -0
  229. package/dist/utils/db.mjs +17 -0
  230. package/dist/utils/db.mjs.map +1 -0
  231. package/dist/utils/deprecate.d.mts +10 -0
  232. package/dist/utils/deprecate.mjs +18 -0
  233. package/dist/utils/deprecate.mjs.map +1 -0
  234. package/dist/utils/error-codes.d.mts +13 -0
  235. package/dist/utils/error-codes.mjs +12 -0
  236. package/dist/utils/error-codes.mjs.map +1 -0
  237. package/dist/utils/id.d.mts +5 -0
  238. package/dist/utils/id.mjs +10 -0
  239. package/dist/utils/id.mjs.map +1 -0
  240. package/dist/utils/ip.d.mts +55 -0
  241. package/dist/utils/ip.mjs +119 -0
  242. package/dist/utils/ip.mjs.map +1 -0
  243. package/dist/utils/json.d.mts +5 -0
  244. package/dist/utils/json.mjs +26 -0
  245. package/dist/utils/json.mjs.map +1 -0
  246. package/dist/utils/string.d.mts +5 -0
  247. package/dist/utils/string.mjs +8 -0
  248. package/dist/utils/string.mjs.map +1 -0
  249. package/dist/utils/url.d.mts +21 -0
  250. package/dist/utils/url.mjs +33 -0
  251. package/dist/utils/url.mjs.map +1 -0
  252. package/package.json +147 -0
  253. package/src/api/index.ts +106 -0
  254. package/src/async_hooks/index.ts +40 -0
  255. package/src/async_hooks/pure.index.ts +46 -0
  256. package/src/context/endpoint-context.ts +50 -0
  257. package/src/context/global.ts +57 -0
  258. package/src/context/index.ts +23 -0
  259. package/src/context/request-state.test.ts +94 -0
  260. package/src/context/request-state.ts +91 -0
  261. package/src/context/transaction.ts +136 -0
  262. package/src/db/adapter/factory.ts +1362 -0
  263. package/src/db/adapter/get-default-field-name.ts +59 -0
  264. package/src/db/adapter/get-default-model-name.ts +51 -0
  265. package/src/db/adapter/get-field-attributes.ts +62 -0
  266. package/src/db/adapter/get-field-name.ts +43 -0
  267. package/src/db/adapter/get-id-field.ts +141 -0
  268. package/src/db/adapter/get-model-name.ts +36 -0
  269. package/src/db/adapter/index.ts +554 -0
  270. package/src/db/adapter/types.ts +171 -0
  271. package/src/db/adapter/utils.ts +61 -0
  272. package/src/db/get-tables.ts +296 -0
  273. package/src/db/index.ts +18 -0
  274. package/src/db/plugin.ts +11 -0
  275. package/src/db/schema/account.ts +34 -0
  276. package/src/db/schema/rate-limit.ts +21 -0
  277. package/src/db/schema/session.ts +17 -0
  278. package/src/db/schema/shared.ts +7 -0
  279. package/src/db/schema/user.ts +16 -0
  280. package/src/db/schema/verification.ts +15 -0
  281. package/src/db/test/get-tables.test.ts +116 -0
  282. package/src/db/type.ts +180 -0
  283. package/src/env/color-depth.ts +172 -0
  284. package/src/env/env-impl.ts +124 -0
  285. package/src/env/index.ts +23 -0
  286. package/src/env/logger.test.ts +34 -0
  287. package/src/env/logger.ts +145 -0
  288. package/src/error/codes.ts +58 -0
  289. package/src/error/index.ts +35 -0
  290. package/src/index.ts +1 -0
  291. package/src/oauth2/client-credentials-token.ts +102 -0
  292. package/src/oauth2/create-authorization-url.ts +87 -0
  293. package/src/oauth2/index.ts +26 -0
  294. package/src/oauth2/oauth-provider.ts +222 -0
  295. package/src/oauth2/refresh-access-token.ts +124 -0
  296. package/src/oauth2/utils.ts +38 -0
  297. package/src/oauth2/validate-authorization-code.ts +149 -0
  298. package/src/oauth2/validate-token.test.ts +174 -0
  299. package/src/oauth2/verify.ts +221 -0
  300. package/src/social-providers/apple.ts +223 -0
  301. package/src/social-providers/atlassian.ts +132 -0
  302. package/src/social-providers/cognito.ts +279 -0
  303. package/src/social-providers/discord.ts +169 -0
  304. package/src/social-providers/dropbox.ts +112 -0
  305. package/src/social-providers/facebook.ts +206 -0
  306. package/src/social-providers/figma.ts +117 -0
  307. package/src/social-providers/github.ts +184 -0
  308. package/src/social-providers/gitlab.ts +155 -0
  309. package/src/social-providers/google.ts +199 -0
  310. package/src/social-providers/huggingface.ts +118 -0
  311. package/src/social-providers/index.ts +127 -0
  312. package/src/social-providers/kakao.ts +178 -0
  313. package/src/social-providers/kick.ts +109 -0
  314. package/src/social-providers/line.ts +169 -0
  315. package/src/social-providers/linear.ts +121 -0
  316. package/src/social-providers/linkedin.ts +110 -0
  317. package/src/social-providers/microsoft-entra-id.ts +259 -0
  318. package/src/social-providers/naver.ts +112 -0
  319. package/src/social-providers/notion.ts +108 -0
  320. package/src/social-providers/paybin.ts +122 -0
  321. package/src/social-providers/paypal.ts +263 -0
  322. package/src/social-providers/polar.ts +110 -0
  323. package/src/social-providers/reddit.ts +122 -0
  324. package/src/social-providers/roblox.ts +111 -0
  325. package/src/social-providers/salesforce.ts +159 -0
  326. package/src/social-providers/slack.ts +111 -0
  327. package/src/social-providers/spotify.ts +93 -0
  328. package/src/social-providers/tiktok.ts +209 -0
  329. package/src/social-providers/twitch.ts +111 -0
  330. package/src/social-providers/twitter.ts +198 -0
  331. package/src/social-providers/vercel.ts +87 -0
  332. package/src/social-providers/vk.ts +124 -0
  333. package/src/social-providers/zoom.ts +238 -0
  334. package/src/types/context.ts +396 -0
  335. package/src/types/cookie.ts +10 -0
  336. package/src/types/helper.ts +26 -0
  337. package/src/types/index.ts +32 -0
  338. package/src/types/init-options.ts +1529 -0
  339. package/src/types/plugin-client.ts +127 -0
  340. package/src/types/plugin.ts +157 -0
  341. package/src/utils/db.ts +20 -0
  342. package/src/utils/deprecate.test.ts +72 -0
  343. package/src/utils/deprecate.ts +21 -0
  344. package/src/utils/error-codes.ts +65 -0
  345. package/src/utils/id.ts +5 -0
  346. package/src/utils/ip.test.ts +255 -0
  347. package/src/utils/ip.ts +211 -0
  348. package/src/utils/json.ts +25 -0
  349. package/src/utils/string.ts +3 -0
  350. package/src/utils/url.ts +43 -0
  351. package/tsconfig.json +7 -0
  352. package/tsdown.config.ts +35 -0
  353. 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,5 @@
1
+ //#region src/utils/id.d.ts
2
+ declare const generateId: (size?: number) => string;
3
+ //#endregion
4
+ export { generateId };
5
+ //# sourceMappingURL=id.d.mts.map
@@ -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":"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"}
@@ -0,0 +1,5 @@
1
+ //#region src/utils/json.d.ts
2
+ declare function safeJSONParse<T>(data: unknown): T | null;
3
+ //#endregion
4
+ export { safeJSONParse };
5
+ //# sourceMappingURL=json.d.mts.map
@@ -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,5 @@
1
+ //#region src/utils/string.d.ts
2
+ declare function capitalizeFirstLetter(str: string): string;
3
+ //#endregion
4
+ export { capitalizeFirstLetter };
5
+ //# sourceMappingURL=string.d.mts.map
@@ -0,0 +1,8 @@
1
+ //#region src/utils/string.ts
2
+ function capitalizeFirstLetter(str) {
3
+ return str.charAt(0).toUpperCase() + str.slice(1);
4
+ }
5
+
6
+ //#endregion
7
+ export { capitalizeFirstLetter };
8
+ //# sourceMappingURL=string.mjs.map
@@ -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