@better-auth/core 1.5.5 → 1.5.7-beta.1

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 (252) hide show
  1. package/dist/api/index.d.mts +41 -14
  2. package/dist/api/index.mjs +1 -2
  3. package/dist/api/index.mjs.map +1 -1
  4. package/dist/async_hooks/index.mjs +1 -1
  5. package/dist/async_hooks/pure.index.mjs +1 -1
  6. package/dist/async_hooks/pure.index.mjs.map +1 -1
  7. package/dist/context/endpoint-context.d.mts +1 -2
  8. package/dist/context/endpoint-context.mjs +1 -2
  9. package/dist/context/endpoint-context.mjs.map +1 -1
  10. package/dist/context/global.mjs +2 -2
  11. package/dist/context/global.mjs.map +1 -1
  12. package/dist/context/index.mjs +1 -2
  13. package/dist/context/request-state.mjs +1 -2
  14. package/dist/context/request-state.mjs.map +1 -1
  15. package/dist/context/transaction.mjs +1 -2
  16. package/dist/context/transaction.mjs.map +1 -1
  17. package/dist/db/adapter/factory.d.mts +0 -2
  18. package/dist/db/adapter/factory.mjs +54 -22
  19. package/dist/db/adapter/factory.mjs.map +1 -1
  20. package/dist/db/adapter/get-default-field-name.mjs +1 -2
  21. package/dist/db/adapter/get-default-field-name.mjs.map +1 -1
  22. package/dist/db/adapter/get-default-model-name.mjs +1 -2
  23. package/dist/db/adapter/get-default-model-name.mjs.map +1 -1
  24. package/dist/db/adapter/get-field-attributes.d.mts +0 -3
  25. package/dist/db/adapter/get-field-attributes.mjs +1 -2
  26. package/dist/db/adapter/get-field-attributes.mjs.map +1 -1
  27. package/dist/db/adapter/get-field-name.mjs +1 -2
  28. package/dist/db/adapter/get-field-name.mjs.map +1 -1
  29. package/dist/db/adapter/get-id-field.d.mts +0 -3
  30. package/dist/db/adapter/get-id-field.mjs +3 -4
  31. package/dist/db/adapter/get-id-field.mjs.map +1 -1
  32. package/dist/db/adapter/get-model-name.mjs +1 -2
  33. package/dist/db/adapter/get-model-name.mjs.map +1 -1
  34. package/dist/db/adapter/index.d.mts +0 -2
  35. package/dist/db/adapter/index.mjs +1 -2
  36. package/dist/db/adapter/index.mjs.map +1 -1
  37. package/dist/db/adapter/types.d.mts +0 -2
  38. package/dist/db/adapter/utils.mjs +1 -1
  39. package/dist/db/adapter/utils.mjs.map +1 -1
  40. package/dist/db/get-tables.d.mts +0 -2
  41. package/dist/db/get-tables.mjs +1 -1
  42. package/dist/db/index.mjs +1 -2
  43. package/dist/db/schema/account.d.mts +0 -1
  44. package/dist/db/schema/account.mjs +1 -2
  45. package/dist/db/schema/account.mjs.map +1 -1
  46. package/dist/db/schema/rate-limit.d.mts +0 -1
  47. package/dist/db/schema/rate-limit.mjs +1 -2
  48. package/dist/db/schema/rate-limit.mjs.map +1 -1
  49. package/dist/db/schema/session.d.mts +0 -1
  50. package/dist/db/schema/session.mjs +1 -2
  51. package/dist/db/schema/session.mjs.map +1 -1
  52. package/dist/db/schema/shared.mjs +1 -2
  53. package/dist/db/schema/shared.mjs.map +1 -1
  54. package/dist/db/schema/user.d.mts +0 -1
  55. package/dist/db/schema/user.mjs +1 -2
  56. package/dist/db/schema/user.mjs.map +1 -1
  57. package/dist/db/schema/verification.d.mts +0 -1
  58. package/dist/db/schema/verification.mjs +1 -2
  59. package/dist/db/schema/verification.mjs.map +1 -1
  60. package/dist/db/type.d.mts +0 -1
  61. package/dist/env/color-depth.mjs +1 -2
  62. package/dist/env/color-depth.mjs.map +1 -1
  63. package/dist/env/env-impl.mjs +1 -1
  64. package/dist/env/env-impl.mjs.map +1 -1
  65. package/dist/env/index.mjs +1 -2
  66. package/dist/env/logger.mjs +1 -2
  67. package/dist/env/logger.mjs.map +1 -1
  68. package/dist/error/codes.mjs +1 -2
  69. package/dist/error/codes.mjs.map +1 -1
  70. package/dist/error/index.mjs +1 -2
  71. package/dist/error/index.mjs.map +1 -1
  72. package/dist/index.mjs +1 -1
  73. package/dist/instrumentation/attributes.d.mts +12 -0
  74. package/dist/instrumentation/attributes.mjs +12 -0
  75. package/dist/instrumentation/attributes.mjs.map +1 -0
  76. package/dist/instrumentation/index.d.mts +3 -0
  77. package/dist/instrumentation/index.mjs +3 -0
  78. package/dist/instrumentation/tracer.d.mts +14 -0
  79. package/dist/instrumentation/tracer.mjs +36 -0
  80. package/dist/instrumentation/tracer.mjs.map +1 -0
  81. package/dist/oauth2/client-credentials-token.d.mts +0 -1
  82. package/dist/oauth2/client-credentials-token.mjs +1 -2
  83. package/dist/oauth2/client-credentials-token.mjs.map +1 -1
  84. package/dist/oauth2/create-authorization-url.d.mts +0 -3
  85. package/dist/oauth2/create-authorization-url.mjs +1 -2
  86. package/dist/oauth2/create-authorization-url.mjs.map +1 -1
  87. package/dist/oauth2/index.mjs +1 -2
  88. package/dist/oauth2/oauth-provider.d.mts +0 -2
  89. package/dist/oauth2/refresh-access-token.d.mts +0 -1
  90. package/dist/oauth2/refresh-access-token.mjs +1 -2
  91. package/dist/oauth2/refresh-access-token.mjs.map +1 -1
  92. package/dist/oauth2/utils.mjs +1 -2
  93. package/dist/oauth2/utils.mjs.map +1 -1
  94. package/dist/oauth2/validate-authorization-code.d.mts +0 -2
  95. package/dist/oauth2/validate-authorization-code.mjs +1 -2
  96. package/dist/oauth2/validate-authorization-code.mjs.map +1 -1
  97. package/dist/oauth2/verify.mjs +1 -2
  98. package/dist/oauth2/verify.mjs.map +1 -1
  99. package/dist/social-providers/apple.d.mts +0 -2
  100. package/dist/social-providers/apple.mjs +2 -3
  101. package/dist/social-providers/apple.mjs.map +1 -1
  102. package/dist/social-providers/atlassian.d.mts +0 -2
  103. package/dist/social-providers/atlassian.mjs +4 -4
  104. package/dist/social-providers/atlassian.mjs.map +1 -1
  105. package/dist/social-providers/cognito.d.mts +0 -2
  106. package/dist/social-providers/cognito.mjs +1 -2
  107. package/dist/social-providers/cognito.mjs.map +1 -1
  108. package/dist/social-providers/discord.d.mts +0 -2
  109. package/dist/social-providers/discord.mjs +4 -4
  110. package/dist/social-providers/discord.mjs.map +1 -1
  111. package/dist/social-providers/dropbox.d.mts +0 -2
  112. package/dist/social-providers/dropbox.mjs +1 -2
  113. package/dist/social-providers/dropbox.mjs.map +1 -1
  114. package/dist/social-providers/facebook.d.mts +0 -2
  115. package/dist/social-providers/facebook.mjs +1 -2
  116. package/dist/social-providers/facebook.mjs.map +1 -1
  117. package/dist/social-providers/figma.d.mts +0 -2
  118. package/dist/social-providers/figma.mjs +4 -4
  119. package/dist/social-providers/figma.mjs.map +1 -1
  120. package/dist/social-providers/github.d.mts +0 -2
  121. package/dist/social-providers/github.mjs +2 -3
  122. package/dist/social-providers/github.mjs.map +1 -1
  123. package/dist/social-providers/gitlab.d.mts +0 -2
  124. package/dist/social-providers/gitlab.mjs +1 -2
  125. package/dist/social-providers/gitlab.mjs.map +1 -1
  126. package/dist/social-providers/google.d.mts +0 -2
  127. package/dist/social-providers/google.mjs +1 -2
  128. package/dist/social-providers/google.mjs.map +1 -1
  129. package/dist/social-providers/huggingface.d.mts +0 -2
  130. package/dist/social-providers/huggingface.mjs +4 -4
  131. package/dist/social-providers/huggingface.mjs.map +1 -1
  132. package/dist/social-providers/index.d.mts +61 -3
  133. package/dist/social-providers/index.mjs +5 -4
  134. package/dist/social-providers/index.mjs.map +1 -1
  135. package/dist/social-providers/kakao.d.mts +0 -2
  136. package/dist/social-providers/kakao.mjs +4 -4
  137. package/dist/social-providers/kakao.mjs.map +1 -1
  138. package/dist/social-providers/kick.d.mts +0 -2
  139. package/dist/social-providers/kick.mjs +1 -2
  140. package/dist/social-providers/kick.mjs.map +1 -1
  141. package/dist/social-providers/line.d.mts +0 -2
  142. package/dist/social-providers/line.mjs +1 -2
  143. package/dist/social-providers/line.mjs.map +1 -1
  144. package/dist/social-providers/linear.d.mts +0 -2
  145. package/dist/social-providers/linear.mjs +1 -2
  146. package/dist/social-providers/linear.mjs.map +1 -1
  147. package/dist/social-providers/linkedin.d.mts +0 -2
  148. package/dist/social-providers/linkedin.mjs +1 -2
  149. package/dist/social-providers/linkedin.mjs.map +1 -1
  150. package/dist/social-providers/microsoft-entra-id.d.mts +0 -2
  151. package/dist/social-providers/microsoft-entra-id.mjs +1 -2
  152. package/dist/social-providers/microsoft-entra-id.mjs.map +1 -1
  153. package/dist/social-providers/naver.d.mts +0 -2
  154. package/dist/social-providers/naver.mjs +4 -4
  155. package/dist/social-providers/naver.mjs.map +1 -1
  156. package/dist/social-providers/notion.d.mts +0 -2
  157. package/dist/social-providers/notion.mjs +1 -2
  158. package/dist/social-providers/notion.mjs.map +1 -1
  159. package/dist/social-providers/paybin.d.mts +0 -2
  160. package/dist/social-providers/paybin.mjs +1 -2
  161. package/dist/social-providers/paybin.mjs.map +1 -1
  162. package/dist/social-providers/paypal.d.mts +0 -2
  163. package/dist/social-providers/paypal.mjs +1 -2
  164. package/dist/social-providers/paypal.mjs.map +1 -1
  165. package/dist/social-providers/polar.d.mts +0 -2
  166. package/dist/social-providers/polar.mjs +4 -4
  167. package/dist/social-providers/polar.mjs.map +1 -1
  168. package/dist/social-providers/railway.d.mts +0 -2
  169. package/dist/social-providers/railway.mjs +1 -2
  170. package/dist/social-providers/railway.mjs.map +1 -1
  171. package/dist/social-providers/reddit.d.mts +0 -2
  172. package/dist/social-providers/reddit.mjs +1 -2
  173. package/dist/social-providers/reddit.mjs.map +1 -1
  174. package/dist/social-providers/roblox.d.mts +0 -2
  175. package/dist/social-providers/roblox.mjs +4 -4
  176. package/dist/social-providers/roblox.mjs.map +1 -1
  177. package/dist/social-providers/salesforce.d.mts +0 -2
  178. package/dist/social-providers/salesforce.mjs +1 -2
  179. package/dist/social-providers/salesforce.mjs.map +1 -1
  180. package/dist/social-providers/slack.d.mts +0 -2
  181. package/dist/social-providers/slack.mjs +4 -4
  182. package/dist/social-providers/slack.mjs.map +1 -1
  183. package/dist/social-providers/spotify.d.mts +0 -2
  184. package/dist/social-providers/spotify.mjs +4 -4
  185. package/dist/social-providers/spotify.mjs.map +1 -1
  186. package/dist/social-providers/tiktok.d.mts +0 -2
  187. package/dist/social-providers/tiktok.mjs +4 -4
  188. package/dist/social-providers/tiktok.mjs.map +1 -1
  189. package/dist/social-providers/twitch.d.mts +0 -2
  190. package/dist/social-providers/twitch.mjs +4 -4
  191. package/dist/social-providers/twitch.mjs.map +1 -1
  192. package/dist/social-providers/twitter.d.mts +0 -2
  193. package/dist/social-providers/twitter.mjs +4 -4
  194. package/dist/social-providers/twitter.mjs.map +1 -1
  195. package/dist/social-providers/vercel.d.mts +0 -2
  196. package/dist/social-providers/vercel.mjs +1 -2
  197. package/dist/social-providers/vercel.mjs.map +1 -1
  198. package/dist/social-providers/vk.d.mts +0 -2
  199. package/dist/social-providers/vk.mjs +4 -4
  200. package/dist/social-providers/vk.mjs.map +1 -1
  201. package/dist/social-providers/wechat.d.mts +114 -0
  202. package/dist/social-providers/wechat.mjs +83 -0
  203. package/dist/social-providers/wechat.mjs.map +1 -0
  204. package/dist/social-providers/zoom.d.mts +0 -2
  205. package/dist/social-providers/zoom.mjs +1 -2
  206. package/dist/social-providers/zoom.mjs.map +1 -1
  207. package/dist/types/context.d.mts +1 -5
  208. package/dist/types/init-options.d.mts +0 -1
  209. package/dist/types/plugin.d.mts +4 -2
  210. package/dist/utils/db.d.mts +0 -2
  211. package/dist/utils/db.mjs +1 -1
  212. package/dist/utils/deprecate.mjs +1 -1
  213. package/dist/utils/error-codes.mjs +1 -1
  214. package/dist/utils/fetch-metadata.mjs +1 -1
  215. package/dist/utils/id.mjs +1 -2
  216. package/dist/utils/id.mjs.map +1 -1
  217. package/dist/utils/ip.mjs +1 -2
  218. package/dist/utils/ip.mjs.map +1 -1
  219. package/dist/utils/json.mjs +1 -2
  220. package/dist/utils/json.mjs.map +1 -1
  221. package/dist/utils/string.mjs +1 -1
  222. package/dist/utils/url.mjs +1 -1
  223. package/package.json +18 -5
  224. package/src/api/index.ts +151 -41
  225. package/src/context/endpoint-context.ts +2 -1
  226. package/src/db/adapter/factory.ts +119 -47
  227. package/src/db/adapter/get-id-field.test.ts +222 -0
  228. package/src/db/adapter/get-id-field.ts +15 -4
  229. package/src/instrumentation/attributes.ts +22 -0
  230. package/src/instrumentation/index.ts +2 -0
  231. package/src/instrumentation/instrumentation.test.ts +139 -0
  232. package/src/instrumentation/tracer.ts +62 -0
  233. package/src/social-providers/apple.ts +1 -1
  234. package/src/social-providers/atlassian.ts +3 -2
  235. package/src/social-providers/discord.ts +3 -2
  236. package/src/social-providers/figma.ts +3 -2
  237. package/src/social-providers/github.ts +1 -1
  238. package/src/social-providers/huggingface.ts +3 -2
  239. package/src/social-providers/index.ts +3 -0
  240. package/src/social-providers/kakao.ts +3 -2
  241. package/src/social-providers/naver.ts +3 -2
  242. package/src/social-providers/polar.ts +3 -2
  243. package/src/social-providers/roblox.ts +3 -2
  244. package/src/social-providers/slack.ts +3 -2
  245. package/src/social-providers/spotify.ts +3 -2
  246. package/src/social-providers/tiktok.ts +3 -2
  247. package/src/social-providers/twitch.ts +3 -2
  248. package/src/social-providers/twitter.ts +3 -2
  249. package/src/social-providers/vk.ts +3 -2
  250. package/src/social-providers/wechat.ts +213 -0
  251. package/src/types/context.ts +1 -3
  252. package/src/types/plugin.ts +14 -1
@@ -1 +1 @@
1
- {"version":3,"file":"zoom.mjs","names":[],"sources":["../../src/social-providers/zoom.ts"],"sourcesContent":["import { betterFetch } from \"@better-fetch/fetch\";\nimport type { OAuthProvider, ProviderOptions } from \"../oauth2\";\nimport {\n\tgenerateCodeChallenge,\n\trefreshAccessToken,\n\tvalidateAuthorizationCode,\n} from \"../oauth2\";\n\nexport type LoginType =\n\t| 0 /** Facebook OAuth */\n\t| 1 /** Google OAuth */\n\t| 24 /** Apple OAuth */\n\t| 27 /** Microsoft OAuth */\n\t| 97 /** Mobile device */\n\t| 98 /** RingCentral OAuth */\n\t| 99 /** API user */\n\t| 100 /** Zoom Work email */\n\t| 101; /** Single Sign-On (SSO) */\n\nexport type AccountStatus = \"pending\" | \"active\" | \"inactive\";\n\nexport type PronounOption =\n\t| 1 /** Ask the user every time */\n\t| 2 /** Always display */\n\t| 3; /** Do not display */\n\nexport interface PhoneNumber {\n\t/** The country code of the phone number (Example: \"+1\") */\n\tcode: string;\n\n\t/** The country of the phone number (Example: \"US\") */\n\tcountry: string;\n\n\t/** The label for the phone number (Example: \"Mobile\") */\n\tlabel: string;\n\n\t/** The phone number itself (Example: \"800000000\") */\n\tnumber: string;\n\n\t/** Whether the phone number has been verified (Example: true) */\n\tverified: boolean;\n}\n\n/**\n * See the full documentation below:\n * https://developers.zoom.us/docs/api/users/#tag/users/GET/users/{userId}\n */\nexport interface ZoomProfile extends Record<string, any> {\n\t/* cspell:disable-next-line */\n\t/** The user's account ID (Example: \"q6gBJVO5TzexKYTb_I2rpg\") */\n\taccount_id: string;\n\t/** The user's account number (Example: 10009239) */\n\taccount_number: number;\n\t/** The user's cluster (Example: \"us04\") */\n\tcluster: string;\n\t/** The user's CMS ID. Only enabled for Kaltura integration (Example: \"KDcuGIm1QgePTO8WbOqwIQ\") */\n\tcms_user_id: string;\n\t/** The user's cost center (Example: \"cost center\") */\n\tcost_center: string;\n\t/** User create time (Example: \"2018-10-31T04:32:37Z\") */\n\tcreated_at: string;\n\t/** Department (Example: \"Developers\") */\n\tdept: string;\n\t/** User's display name (Example: \"Jill Chill\") */\n\tdisplay_name: string;\n\t/** User's email address (Example: \"jchill@example.com\") */\n\temail: string;\n\t/** User's first name (Example: \"Jill\") */\n\tfirst_name: string;\n\t/* cspell:disable-next-line */\n\t/** IDs of the web groups that the user belongs to (Example: [\"RSMaSp8sTEGK0_oamiA2_w\"]) */\n\tgroup_ids: string[];\n\t/* cspell:disable-next-line */\n\t/** User ID (Example: \"zJKyaiAyTNC-MWjiWC18KQ\") */\n\tid: string;\n\t/* cspell:disable-next-line */\n\t/** IM IDs of the groups that the user belongs to (Example: [\"t-_-d56CSWG-7BF15LLrOw\"]) */\n\tim_group_ids: string[];\n\t/** The user's JID (Example: \"jchill@example.com\") */\n\tjid: string;\n\t/** The user's job title (Example: \"API Developer\") */\n\tjob_title: string;\n\t/** Default language for the Zoom Web Portal (Example: \"en-US\") */\n\tlanguage: string;\n\t/** User last login client version (Example: \"5.9.6.4993(mac)\") */\n\tlast_client_version: string;\n\t/** User last login time (Example: \"2021-05-05T20:40:30Z\") */\n\tlast_login_time: string;\n\t/** User's last name (Example: \"Chill\") */\n\tlast_name: string;\n\t/** The time zone of the user (Example: \"Asia/Shanghai\") */\n\ttimezone: string;\n\t/** User's location (Example: \"Paris\") */\n\tlocation: string;\n\t/** The user's login method (Example: 101) */\n\tlogin_types: LoginType[];\n\t/** User's personal meeting URL (Example: \"example.com\") */\n\tpersonal_meeting_url: string;\n\t/** The URL for user's profile picture (Example: \"example.com\") */\n\tpic_url: string;\n\t/** Personal Meeting ID (PMI) (Example: 3542471135) */\n\tpmi: number;\n\t/** Unique identifier of the user's assigned role (Example: \"0\") */\n\trole_id: string;\n\t/** User's role name (Example: \"Admin\") */\n\trole_name: string;\n\t/** Status of user's account (Example: \"pending\") */\n\tstatus: AccountStatus;\n\t/** Use the personal meeting ID (PMI) for instant meetings (Example: false) */\n\tuse_pmi: boolean;\n\t/** The time and date when the user was created (Example: \"2018-10-31T04:32:37Z\") */\n\tuser_created_at: string;\n\t/** Displays whether user is verified or not (Example: 1) */\n\tverified: number;\n\t/** The user's Zoom Workplace plan option (Example: 64) */\n\tzoom_one_type: number;\n\t/** The user's company (Example: \"Jill\") */\n\tcompany?: string | undefined;\n\t/* cspell:disable-next-line */\n\t/** Custom attributes that have been assigned to the user (Example: [{ \"key\": \"cbf_cywdkexrtqc73f97gd4w6g\", \"name\": \"A1\", \"value\": \"1\" }]) */\n\tcustom_attributes?:\n\t\t| { key: string; name: string; value: string }[]\n\t\t| undefined;\n\t/* cspell:disable-next-line */\n\t/** The employee's unique ID. This field only returns when SAML single sign-on (SSO) is enabled. The `login_type` value is `101` (SSO) (Example: \"HqDyI037Qjili1kNsSIrIg\") */\n\temployee_unique_id?: string | undefined;\n\t/** The manager for the user (Example: \"thill@example.com\") */\n\tmanager?: string | undefined;\n\t/** The phone number's ISO country code (Example: \"+1\") */\n\tphone_numbers?: PhoneNumber[] | undefined;\n\t/** The user's plan type (Example: \"1\") */\n\tplan_united_type?: string | undefined;\n\t/** The user's pronouns (Example: \"3123\") */\n\tpronouns?: string | undefined;\n\t/** The user's display pronouns setting (Example: 1) */\n\tpronouns_option?: PronounOption | undefined;\n\t/** Personal meeting room URL, if the user has one (Example: \"example.com\") */\n\tvanity_url?: string | undefined;\n}\n\nexport interface ZoomOptions extends ProviderOptions<ZoomProfile> {\n\tclientId: string;\n\tpkce?: boolean | undefined;\n}\n\nexport const zoom = (userOptions: ZoomOptions) => {\n\tconst options = {\n\t\tpkce: true,\n\t\t...userOptions,\n\t};\n\n\treturn {\n\t\tid: \"zoom\",\n\t\tname: \"Zoom\",\n\t\tcreateAuthorizationURL: async ({ state, redirectURI, codeVerifier }) => {\n\t\t\tconst params = new URLSearchParams({\n\t\t\t\tresponse_type: \"code\",\n\t\t\t\tredirect_uri: options.redirectURI ? options.redirectURI : redirectURI,\n\t\t\t\tclient_id: options.clientId,\n\t\t\t\tstate,\n\t\t\t});\n\n\t\t\tif (options.pkce) {\n\t\t\t\tconst codeChallenge = await generateCodeChallenge(codeVerifier);\n\t\t\t\tparams.set(\"code_challenge_method\", \"S256\");\n\t\t\t\tparams.set(\"code_challenge\", codeChallenge);\n\t\t\t}\n\n\t\t\tconst url = new URL(\"https://zoom.us/oauth/authorize\");\n\t\t\turl.search = params.toString();\n\n\t\t\treturn url;\n\t\t},\n\t\tvalidateAuthorizationCode: async ({ code, redirectURI, codeVerifier }) => {\n\t\t\treturn validateAuthorizationCode({\n\t\t\t\tcode,\n\t\t\t\tredirectURI: options.redirectURI || redirectURI,\n\t\t\t\tcodeVerifier,\n\t\t\t\toptions,\n\t\t\t\ttokenEndpoint: \"https://zoom.us/oauth/token\",\n\t\t\t\tauthentication: \"post\",\n\t\t\t});\n\t\t},\n\t\trefreshAccessToken: options.refreshAccessToken\n\t\t\t? options.refreshAccessToken\n\t\t\t: async (refreshToken) =>\n\t\t\t\t\trefreshAccessToken({\n\t\t\t\t\t\trefreshToken,\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tclientId: options.clientId,\n\t\t\t\t\t\t\tclientKey: options.clientKey,\n\t\t\t\t\t\t\tclientSecret: options.clientSecret,\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttokenEndpoint: \"https://zoom.us/oauth/token\",\n\t\t\t\t\t}),\n\t\tasync getUserInfo(token) {\n\t\t\tif (options.getUserInfo) {\n\t\t\t\treturn options.getUserInfo(token);\n\t\t\t}\n\t\t\tconst { data: profile, error } = await betterFetch<ZoomProfile>(\n\t\t\t\t\"https://api.zoom.us/v2/users/me\",\n\t\t\t\t{\n\t\t\t\t\theaders: {\n\t\t\t\t\t\tauthorization: `Bearer ${token.accessToken}`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tif (error) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst userMap = await options.mapProfileToUser?.(profile);\n\n\t\t\treturn {\n\t\t\t\tuser: {\n\t\t\t\t\tid: profile.id,\n\t\t\t\t\tname: profile.display_name,\n\t\t\t\t\timage: profile.pic_url,\n\t\t\t\t\temail: profile.email,\n\t\t\t\t\temailVerified: Boolean(profile.verified),\n\t\t\t\t\t...userMap,\n\t\t\t\t},\n\t\t\t\tdata: {\n\t\t\t\t\t...profile,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t} satisfies OAuthProvider<ZoomProfile>;\n};\n"],"mappings":";;;;;;;AAiJA,MAAa,QAAQ,gBAA6B;CACjD,MAAM,UAAU;EACf,MAAM;EACN,GAAG;EACH;AAED,QAAO;EACN,IAAI;EACJ,MAAM;EACN,wBAAwB,OAAO,EAAE,OAAO,aAAa,mBAAmB;GACvE,MAAM,SAAS,IAAI,gBAAgB;IAClC,eAAe;IACf,cAAc,QAAQ,cAAc,QAAQ,cAAc;IAC1D,WAAW,QAAQ;IACnB;IACA,CAAC;AAEF,OAAI,QAAQ,MAAM;IACjB,MAAM,gBAAgB,MAAM,sBAAsB,aAAa;AAC/D,WAAO,IAAI,yBAAyB,OAAO;AAC3C,WAAO,IAAI,kBAAkB,cAAc;;GAG5C,MAAM,MAAM,IAAI,IAAI,kCAAkC;AACtD,OAAI,SAAS,OAAO,UAAU;AAE9B,UAAO;;EAER,2BAA2B,OAAO,EAAE,MAAM,aAAa,mBAAmB;AACzE,UAAO,0BAA0B;IAChC;IACA,aAAa,QAAQ,eAAe;IACpC;IACA;IACA,eAAe;IACf,gBAAgB;IAChB,CAAC;;EAEH,oBAAoB,QAAQ,qBACzB,QAAQ,qBACR,OAAO,iBACP,mBAAmB;GAClB;GACA,SAAS;IACR,UAAU,QAAQ;IAClB,WAAW,QAAQ;IACnB,cAAc,QAAQ;IACtB;GACD,eAAe;GACf,CAAC;EACL,MAAM,YAAY,OAAO;AACxB,OAAI,QAAQ,YACX,QAAO,QAAQ,YAAY,MAAM;GAElC,MAAM,EAAE,MAAM,SAAS,UAAU,MAAM,YACtC,mCACA,EACC,SAAS,EACR,eAAe,UAAU,MAAM,eAC/B,EACD,CACD;AAED,OAAI,MACH,QAAO;GAGR,MAAM,UAAU,MAAM,QAAQ,mBAAmB,QAAQ;AAEzD,UAAO;IACN,MAAM;KACL,IAAI,QAAQ;KACZ,MAAM,QAAQ;KACd,OAAO,QAAQ;KACf,OAAO,QAAQ;KACf,eAAe,QAAQ,QAAQ,SAAS;KACxC,GAAG;KACH;IACD,MAAM,EACL,GAAG,SACH;IACD;;EAEF"}
1
+ {"version":3,"file":"zoom.mjs","names":[],"sources":["../../src/social-providers/zoom.ts"],"sourcesContent":["import { betterFetch } from \"@better-fetch/fetch\";\nimport type { OAuthProvider, ProviderOptions } from \"../oauth2\";\nimport {\n\tgenerateCodeChallenge,\n\trefreshAccessToken,\n\tvalidateAuthorizationCode,\n} from \"../oauth2\";\n\nexport type LoginType =\n\t| 0 /** Facebook OAuth */\n\t| 1 /** Google OAuth */\n\t| 24 /** Apple OAuth */\n\t| 27 /** Microsoft OAuth */\n\t| 97 /** Mobile device */\n\t| 98 /** RingCentral OAuth */\n\t| 99 /** API user */\n\t| 100 /** Zoom Work email */\n\t| 101; /** Single Sign-On (SSO) */\n\nexport type AccountStatus = \"pending\" | \"active\" | \"inactive\";\n\nexport type PronounOption =\n\t| 1 /** Ask the user every time */\n\t| 2 /** Always display */\n\t| 3; /** Do not display */\n\nexport interface PhoneNumber {\n\t/** The country code of the phone number (Example: \"+1\") */\n\tcode: string;\n\n\t/** The country of the phone number (Example: \"US\") */\n\tcountry: string;\n\n\t/** The label for the phone number (Example: \"Mobile\") */\n\tlabel: string;\n\n\t/** The phone number itself (Example: \"800000000\") */\n\tnumber: string;\n\n\t/** Whether the phone number has been verified (Example: true) */\n\tverified: boolean;\n}\n\n/**\n * See the full documentation below:\n * https://developers.zoom.us/docs/api/users/#tag/users/GET/users/{userId}\n */\nexport interface ZoomProfile extends Record<string, any> {\n\t/* cspell:disable-next-line */\n\t/** The user's account ID (Example: \"q6gBJVO5TzexKYTb_I2rpg\") */\n\taccount_id: string;\n\t/** The user's account number (Example: 10009239) */\n\taccount_number: number;\n\t/** The user's cluster (Example: \"us04\") */\n\tcluster: string;\n\t/** The user's CMS ID. Only enabled for Kaltura integration (Example: \"KDcuGIm1QgePTO8WbOqwIQ\") */\n\tcms_user_id: string;\n\t/** The user's cost center (Example: \"cost center\") */\n\tcost_center: string;\n\t/** User create time (Example: \"2018-10-31T04:32:37Z\") */\n\tcreated_at: string;\n\t/** Department (Example: \"Developers\") */\n\tdept: string;\n\t/** User's display name (Example: \"Jill Chill\") */\n\tdisplay_name: string;\n\t/** User's email address (Example: \"jchill@example.com\") */\n\temail: string;\n\t/** User's first name (Example: \"Jill\") */\n\tfirst_name: string;\n\t/* cspell:disable-next-line */\n\t/** IDs of the web groups that the user belongs to (Example: [\"RSMaSp8sTEGK0_oamiA2_w\"]) */\n\tgroup_ids: string[];\n\t/* cspell:disable-next-line */\n\t/** User ID (Example: \"zJKyaiAyTNC-MWjiWC18KQ\") */\n\tid: string;\n\t/* cspell:disable-next-line */\n\t/** IM IDs of the groups that the user belongs to (Example: [\"t-_-d56CSWG-7BF15LLrOw\"]) */\n\tim_group_ids: string[];\n\t/** The user's JID (Example: \"jchill@example.com\") */\n\tjid: string;\n\t/** The user's job title (Example: \"API Developer\") */\n\tjob_title: string;\n\t/** Default language for the Zoom Web Portal (Example: \"en-US\") */\n\tlanguage: string;\n\t/** User last login client version (Example: \"5.9.6.4993(mac)\") */\n\tlast_client_version: string;\n\t/** User last login time (Example: \"2021-05-05T20:40:30Z\") */\n\tlast_login_time: string;\n\t/** User's last name (Example: \"Chill\") */\n\tlast_name: string;\n\t/** The time zone of the user (Example: \"Asia/Shanghai\") */\n\ttimezone: string;\n\t/** User's location (Example: \"Paris\") */\n\tlocation: string;\n\t/** The user's login method (Example: 101) */\n\tlogin_types: LoginType[];\n\t/** User's personal meeting URL (Example: \"example.com\") */\n\tpersonal_meeting_url: string;\n\t/** The URL for user's profile picture (Example: \"example.com\") */\n\tpic_url: string;\n\t/** Personal Meeting ID (PMI) (Example: 3542471135) */\n\tpmi: number;\n\t/** Unique identifier of the user's assigned role (Example: \"0\") */\n\trole_id: string;\n\t/** User's role name (Example: \"Admin\") */\n\trole_name: string;\n\t/** Status of user's account (Example: \"pending\") */\n\tstatus: AccountStatus;\n\t/** Use the personal meeting ID (PMI) for instant meetings (Example: false) */\n\tuse_pmi: boolean;\n\t/** The time and date when the user was created (Example: \"2018-10-31T04:32:37Z\") */\n\tuser_created_at: string;\n\t/** Displays whether user is verified or not (Example: 1) */\n\tverified: number;\n\t/** The user's Zoom Workplace plan option (Example: 64) */\n\tzoom_one_type: number;\n\t/** The user's company (Example: \"Jill\") */\n\tcompany?: string | undefined;\n\t/* cspell:disable-next-line */\n\t/** Custom attributes that have been assigned to the user (Example: [{ \"key\": \"cbf_cywdkexrtqc73f97gd4w6g\", \"name\": \"A1\", \"value\": \"1\" }]) */\n\tcustom_attributes?:\n\t\t| { key: string; name: string; value: string }[]\n\t\t| undefined;\n\t/* cspell:disable-next-line */\n\t/** The employee's unique ID. This field only returns when SAML single sign-on (SSO) is enabled. The `login_type` value is `101` (SSO) (Example: \"HqDyI037Qjili1kNsSIrIg\") */\n\temployee_unique_id?: string | undefined;\n\t/** The manager for the user (Example: \"thill@example.com\") */\n\tmanager?: string | undefined;\n\t/** The phone number's ISO country code (Example: \"+1\") */\n\tphone_numbers?: PhoneNumber[] | undefined;\n\t/** The user's plan type (Example: \"1\") */\n\tplan_united_type?: string | undefined;\n\t/** The user's pronouns (Example: \"3123\") */\n\tpronouns?: string | undefined;\n\t/** The user's display pronouns setting (Example: 1) */\n\tpronouns_option?: PronounOption | undefined;\n\t/** Personal meeting room URL, if the user has one (Example: \"example.com\") */\n\tvanity_url?: string | undefined;\n}\n\nexport interface ZoomOptions extends ProviderOptions<ZoomProfile> {\n\tclientId: string;\n\tpkce?: boolean | undefined;\n}\n\nexport const zoom = (userOptions: ZoomOptions) => {\n\tconst options = {\n\t\tpkce: true,\n\t\t...userOptions,\n\t};\n\n\treturn {\n\t\tid: \"zoom\",\n\t\tname: \"Zoom\",\n\t\tcreateAuthorizationURL: async ({ state, redirectURI, codeVerifier }) => {\n\t\t\tconst params = new URLSearchParams({\n\t\t\t\tresponse_type: \"code\",\n\t\t\t\tredirect_uri: options.redirectURI ? options.redirectURI : redirectURI,\n\t\t\t\tclient_id: options.clientId,\n\t\t\t\tstate,\n\t\t\t});\n\n\t\t\tif (options.pkce) {\n\t\t\t\tconst codeChallenge = await generateCodeChallenge(codeVerifier);\n\t\t\t\tparams.set(\"code_challenge_method\", \"S256\");\n\t\t\t\tparams.set(\"code_challenge\", codeChallenge);\n\t\t\t}\n\n\t\t\tconst url = new URL(\"https://zoom.us/oauth/authorize\");\n\t\t\turl.search = params.toString();\n\n\t\t\treturn url;\n\t\t},\n\t\tvalidateAuthorizationCode: async ({ code, redirectURI, codeVerifier }) => {\n\t\t\treturn validateAuthorizationCode({\n\t\t\t\tcode,\n\t\t\t\tredirectURI: options.redirectURI || redirectURI,\n\t\t\t\tcodeVerifier,\n\t\t\t\toptions,\n\t\t\t\ttokenEndpoint: \"https://zoom.us/oauth/token\",\n\t\t\t\tauthentication: \"post\",\n\t\t\t});\n\t\t},\n\t\trefreshAccessToken: options.refreshAccessToken\n\t\t\t? options.refreshAccessToken\n\t\t\t: async (refreshToken) =>\n\t\t\t\t\trefreshAccessToken({\n\t\t\t\t\t\trefreshToken,\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tclientId: options.clientId,\n\t\t\t\t\t\t\tclientKey: options.clientKey,\n\t\t\t\t\t\t\tclientSecret: options.clientSecret,\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttokenEndpoint: \"https://zoom.us/oauth/token\",\n\t\t\t\t\t}),\n\t\tasync getUserInfo(token) {\n\t\t\tif (options.getUserInfo) {\n\t\t\t\treturn options.getUserInfo(token);\n\t\t\t}\n\t\t\tconst { data: profile, error } = await betterFetch<ZoomProfile>(\n\t\t\t\t\"https://api.zoom.us/v2/users/me\",\n\t\t\t\t{\n\t\t\t\t\theaders: {\n\t\t\t\t\t\tauthorization: `Bearer ${token.accessToken}`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tif (error) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst userMap = await options.mapProfileToUser?.(profile);\n\n\t\t\treturn {\n\t\t\t\tuser: {\n\t\t\t\t\tid: profile.id,\n\t\t\t\t\tname: profile.display_name,\n\t\t\t\t\timage: profile.pic_url,\n\t\t\t\t\temail: profile.email,\n\t\t\t\t\temailVerified: Boolean(profile.verified),\n\t\t\t\t\t...userMap,\n\t\t\t\t},\n\t\t\t\tdata: {\n\t\t\t\t\t...profile,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t} satisfies OAuthProvider<ZoomProfile>;\n};\n"],"mappings":";;;;;;AAiJA,MAAa,QAAQ,gBAA6B;CACjD,MAAM,UAAU;EACf,MAAM;EACN,GAAG;EACH;AAED,QAAO;EACN,IAAI;EACJ,MAAM;EACN,wBAAwB,OAAO,EAAE,OAAO,aAAa,mBAAmB;GACvE,MAAM,SAAS,IAAI,gBAAgB;IAClC,eAAe;IACf,cAAc,QAAQ,cAAc,QAAQ,cAAc;IAC1D,WAAW,QAAQ;IACnB;IACA,CAAC;AAEF,OAAI,QAAQ,MAAM;IACjB,MAAM,gBAAgB,MAAM,sBAAsB,aAAa;AAC/D,WAAO,IAAI,yBAAyB,OAAO;AAC3C,WAAO,IAAI,kBAAkB,cAAc;;GAG5C,MAAM,MAAM,IAAI,IAAI,kCAAkC;AACtD,OAAI,SAAS,OAAO,UAAU;AAE9B,UAAO;;EAER,2BAA2B,OAAO,EAAE,MAAM,aAAa,mBAAmB;AACzE,UAAO,0BAA0B;IAChC;IACA,aAAa,QAAQ,eAAe;IACpC;IACA;IACA,eAAe;IACf,gBAAgB;IAChB,CAAC;;EAEH,oBAAoB,QAAQ,qBACzB,QAAQ,qBACR,OAAO,iBACP,mBAAmB;GAClB;GACA,SAAS;IACR,UAAU,QAAQ;IAClB,WAAW,QAAQ;IACnB,cAAc,QAAQ;IACtB;GACD,eAAe;GACf,CAAC;EACL,MAAM,YAAY,OAAO;AACxB,OAAI,QAAQ,YACX,QAAO,QAAQ,YAAY,MAAM;GAElC,MAAM,EAAE,MAAM,SAAS,UAAU,MAAM,YACtC,mCACA,EACC,SAAS,EACR,eAAe,UAAU,MAAM,eAC/B,EACD,CACD;AAED,OAAI,MACH,QAAO;GAGR,MAAM,UAAU,MAAM,QAAQ,mBAAmB,QAAQ;AAEzD,UAAO;IACN,MAAM;KACL,IAAI,QAAQ;KACZ,MAAM,QAAQ;KACd,OAAO,QAAQ;KACf,OAAO,QAAQ;KACf,eAAe,QAAQ,QAAQ,SAAS;KACxC,GAAG;KACH;IACD,MAAM,EACL,GAAG,SACH;IACD;;EAEF"}
@@ -8,11 +8,9 @@ import { Awaitable, LiteralString } from "./helper.mjs";
8
8
  import { BetterAuthPlugin } from "./plugin.mjs";
9
9
  import { BetterAuthOptions, BetterAuthRateLimitOptions } from "./init-options.mjs";
10
10
  import { Account } from "../db/schema/account.mjs";
11
- import "../db/index.mjs";
12
11
  import { BetterAuthCookie, BetterAuthCookies } from "./cookie.mjs";
13
12
  import { SecretConfig } from "./secret.mjs";
14
13
  import { OAuthProvider } from "../oauth2/oauth-provider.mjs";
15
- import "../oauth2/index.mjs";
16
14
  import { CookieOptions, EndpointContext } from "better-call";
17
15
 
18
16
  //#region src/types/context.d.ts
@@ -51,9 +49,7 @@ type InferPluginOptions<O extends BetterAuthOptions, ID extends BetterAuthPlugin
51
49
  */
52
50
  interface BetterAuthPluginRegistry<AuthOptions, Options> {}
53
51
  type BetterAuthPluginRegistryIdentifier = keyof BetterAuthPluginRegistry<unknown, unknown>;
54
- type GenericEndpointContext<Options extends BetterAuthOptions = BetterAuthOptions> = EndpointContext<string, any> & {
55
- context: AuthContext<Options>;
56
- };
52
+ type GenericEndpointContext<Options extends BetterAuthOptions = BetterAuthOptions> = EndpointContext<string, any, any, any, any, any, any, AuthContext<Options>>;
57
53
  interface InternalAdapter<_Options extends BetterAuthOptions = BetterAuthOptions> {
58
54
  createOAuthUser(user: Omit<User, "id" | "createdAt" | "updatedAt">, account: Omit<Account, "userId" | "id" | "createdAt" | "updatedAt"> & Partial<Account>): Promise<{
59
55
  user: User;
@@ -9,7 +9,6 @@ import { SocialProviderList, SocialProviders } from "../social-providers/index.m
9
9
  import { Awaitable, LiteralString, LiteralUnion } from "./helper.mjs";
10
10
  import { BetterAuthPlugin } from "./plugin.mjs";
11
11
  import { Account, BaseAccount } from "../db/schema/account.mjs";
12
- import "../db/index.mjs";
13
12
  import { AuthContext, GenericEndpointContext } from "./context.mjs";
14
13
  import { AuthMiddleware } from "../api/index.mjs";
15
14
  import { CookieOptions } from "better-call";
@@ -2,7 +2,6 @@ import { BetterAuthPluginDBSchema } from "../db/plugin.mjs";
2
2
  import { Awaitable, LiteralString } from "./helper.mjs";
3
3
  import { RawError } from "../utils/error-codes.mjs";
4
4
  import { BetterAuthOptions } from "./init-options.mjs";
5
- import "../db/index.mjs";
6
5
  import { AuthContext } from "./context.mjs";
7
6
  import { AuthMiddleware } from "../api/index.mjs";
8
7
  import { Endpoint, EndpointContext, InputContext, Middleware } from "better-call";
@@ -10,7 +9,10 @@ import { Migration } from "kysely";
10
9
 
11
10
  //#region src/types/plugin.d.ts
12
11
  type DeepPartial<T> = T extends Function ? T : T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T;
13
- type HookEndpointContext = Partial<EndpointContext<string, any> & Omit<InputContext<string, any>, "method">> & {
12
+ type HookEndpointContext = Partial<EndpointContext<string, any, any, any, any, any, any, AuthContext & {
13
+ returned?: unknown | undefined;
14
+ responseHeaders?: Headers | undefined;
15
+ }> & Omit<InputContext<string, any, any, any, any, any>, "method">> & {
14
16
  path?: string;
15
17
  context: AuthContext & {
16
18
  returned?: unknown | undefined;
@@ -1,6 +1,4 @@
1
1
  import { DBFieldAttribute } from "../db/type.mjs";
2
- import "../db/index.mjs";
3
-
4
2
  //#region src/utils/db.d.ts
5
3
  /**
6
4
  * Filters output data by removing fields with the `returned: false` attribute.
package/dist/utils/db.mjs CHANGED
@@ -11,7 +11,7 @@ function filterOutputFields(data, additionalFields) {
11
11
  [key]: value
12
12
  }), {});
13
13
  }
14
-
15
14
  //#endregion
16
15
  export { filterOutputFields };
16
+
17
17
  //# sourceMappingURL=db.mjs.map
@@ -12,7 +12,7 @@ function deprecate(fn, message, logger) {
12
12
  return fn.apply(this, args);
13
13
  };
14
14
  }
15
-
16
15
  //#endregion
17
16
  export { deprecate };
17
+
18
18
  //# sourceMappingURL=deprecate.mjs.map
@@ -6,7 +6,7 @@ function defineErrorCodes(codes) {
6
6
  toString: () => key
7
7
  }]));
8
8
  }
9
-
10
9
  //#endregion
11
10
  export { defineErrorCodes };
11
+
12
12
  //# sourceMappingURL=error-codes.mjs.map
@@ -2,7 +2,7 @@
2
2
  function isBrowserFetchRequest(headers) {
3
3
  return headers?.get("sec-fetch-mode") === "cors";
4
4
  }
5
-
6
5
  //#endregion
7
6
  export { isBrowserFetchRequest };
7
+
8
8
  //# sourceMappingURL=fetch-metadata.mjs.map
package/dist/utils/id.mjs CHANGED
@@ -1,10 +1,9 @@
1
1
  import { createRandomStringGenerator } from "@better-auth/utils/random";
2
-
3
2
  //#region src/utils/id.ts
4
3
  const generateId = (size) => {
5
4
  return createRandomStringGenerator("a-z", "A-Z", "0-9")(size || 32);
6
5
  };
7
-
8
6
  //#endregion
9
7
  export { generateId };
8
+
10
9
  //# sourceMappingURL=id.mjs.map
@@ -1 +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"}
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"}
package/dist/utils/ip.mjs CHANGED
@@ -1,5 +1,4 @@
1
1
  import * as z from "zod";
2
-
3
2
  //#region src/utils/ip.ts
4
3
  /**
5
4
  * Checks if an IP is valid IPv4 or IPv6
@@ -113,7 +112,7 @@ function normalizeIP(ip, options = {}) {
113
112
  function createRateLimitKey(ip, path) {
114
113
  return `${ip}|${path}`;
115
114
  }
116
-
117
115
  //#endregion
118
116
  export { createRateLimitKey, isValidIP, normalizeIP };
117
+
119
118
  //# sourceMappingURL=ip.mjs.map
@@ -1 +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"}
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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"}
@@ -1,6 +1,5 @@
1
1
  import { logger } from "../env/logger.mjs";
2
2
  import "../env/index.mjs";
3
-
4
3
  //#region src/utils/json.ts
5
4
  const iso8601Regex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/;
6
5
  function reviveDate(value) {
@@ -39,7 +38,7 @@ function safeJSONParse(data) {
39
38
  return null;
40
39
  }
41
40
  }
42
-
43
41
  //#endregion
44
42
  export { safeJSONParse };
43
+
45
44
  //# sourceMappingURL=json.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"json.mjs","names":[],"sources":["../../src/utils/json.ts"],"sourcesContent":["import { logger } from \"../env\";\n\nconst iso8601Regex = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?Z$/;\n\nfunction reviveDate(value: unknown): any {\n\tif (typeof value === \"string\" && iso8601Regex.test(value)) {\n\t\tconst date = new Date(value);\n\t\tif (!isNaN(date.getTime())) {\n\t\t\treturn date;\n\t\t}\n\t}\n\treturn value;\n}\n\n/**\n * Recursively walk a pre-parsed object and convert ISO 8601 date strings\n * to Date instances. This handles the case where a Redis client (or similar)\n * returns already-parsed JSON objects whose date fields are still strings.\n */\nfunction reviveDates(value: unknown): any {\n\tif (value === null || value === undefined) {\n\t\treturn value;\n\t}\n\tif (typeof value === \"string\") {\n\t\treturn reviveDate(value);\n\t}\n\tif (value instanceof Date) {\n\t\treturn value;\n\t}\n\tif (Array.isArray(value)) {\n\t\treturn value.map(reviveDates);\n\t}\n\tif (typeof value === \"object\") {\n\t\tconst result: Record<string, any> = {};\n\t\tfor (const key of Object.keys(value)) {\n\t\t\tresult[key] = reviveDates((value as Record<string, any>)[key]);\n\t\t}\n\t\treturn result;\n\t}\n\treturn value;\n}\n\nexport function safeJSONParse<T>(data: unknown): T | null {\n\ttry {\n\t\tif (typeof data !== \"string\") {\n\t\t\tif (data === null || data === undefined) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn reviveDates(data) as T;\n\t\t}\n\t\treturn JSON.parse(data, (_, value) => reviveDate(value));\n\t} catch (e) {\n\t\tlogger.error(\"Error parsing JSON\", { error: e });\n\t\treturn null;\n\t}\n}\n"],"mappings":";;;;AAEA,MAAM,eAAe;AAErB,SAAS,WAAW,OAAqB;AACxC,KAAI,OAAO,UAAU,YAAY,aAAa,KAAK,MAAM,EAAE;EAC1D,MAAM,OAAO,IAAI,KAAK,MAAM;AAC5B,MAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CACzB,QAAO;;AAGT,QAAO;;;;;;;AAQR,SAAS,YAAY,OAAqB;AACzC,KAAI,UAAU,QAAQ,UAAU,OAC/B,QAAO;AAER,KAAI,OAAO,UAAU,SACpB,QAAO,WAAW,MAAM;AAEzB,KAAI,iBAAiB,KACpB,QAAO;AAER,KAAI,MAAM,QAAQ,MAAM,CACvB,QAAO,MAAM,IAAI,YAAY;AAE9B,KAAI,OAAO,UAAU,UAAU;EAC9B,MAAM,SAA8B,EAAE;AACtC,OAAK,MAAM,OAAO,OAAO,KAAK,MAAM,CACnC,QAAO,OAAO,YAAa,MAA8B,KAAK;AAE/D,SAAO;;AAER,QAAO;;AAGR,SAAgB,cAAiB,MAAyB;AACzD,KAAI;AACH,MAAI,OAAO,SAAS,UAAU;AAC7B,OAAI,SAAS,QAAQ,SAAS,OAC7B,QAAO;AAER,UAAO,YAAY,KAAK;;AAEzB,SAAO,KAAK,MAAM,OAAO,GAAG,UAAU,WAAW,MAAM,CAAC;UAChD,GAAG;AACX,SAAO,MAAM,sBAAsB,EAAE,OAAO,GAAG,CAAC;AAChD,SAAO"}
1
+ {"version":3,"file":"json.mjs","names":[],"sources":["../../src/utils/json.ts"],"sourcesContent":["import { logger } from \"../env\";\n\nconst iso8601Regex = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?Z$/;\n\nfunction reviveDate(value: unknown): any {\n\tif (typeof value === \"string\" && iso8601Regex.test(value)) {\n\t\tconst date = new Date(value);\n\t\tif (!isNaN(date.getTime())) {\n\t\t\treturn date;\n\t\t}\n\t}\n\treturn value;\n}\n\n/**\n * Recursively walk a pre-parsed object and convert ISO 8601 date strings\n * to Date instances. This handles the case where a Redis client (or similar)\n * returns already-parsed JSON objects whose date fields are still strings.\n */\nfunction reviveDates(value: unknown): any {\n\tif (value === null || value === undefined) {\n\t\treturn value;\n\t}\n\tif (typeof value === \"string\") {\n\t\treturn reviveDate(value);\n\t}\n\tif (value instanceof Date) {\n\t\treturn value;\n\t}\n\tif (Array.isArray(value)) {\n\t\treturn value.map(reviveDates);\n\t}\n\tif (typeof value === \"object\") {\n\t\tconst result: Record<string, any> = {};\n\t\tfor (const key of Object.keys(value)) {\n\t\t\tresult[key] = reviveDates((value as Record<string, any>)[key]);\n\t\t}\n\t\treturn result;\n\t}\n\treturn value;\n}\n\nexport function safeJSONParse<T>(data: unknown): T | null {\n\ttry {\n\t\tif (typeof data !== \"string\") {\n\t\t\tif (data === null || data === undefined) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn reviveDates(data) as T;\n\t\t}\n\t\treturn JSON.parse(data, (_, value) => reviveDate(value));\n\t} catch (e) {\n\t\tlogger.error(\"Error parsing JSON\", { error: e });\n\t\treturn null;\n\t}\n}\n"],"mappings":";;;AAEA,MAAM,eAAe;AAErB,SAAS,WAAW,OAAqB;AACxC,KAAI,OAAO,UAAU,YAAY,aAAa,KAAK,MAAM,EAAE;EAC1D,MAAM,OAAO,IAAI,KAAK,MAAM;AAC5B,MAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CACzB,QAAO;;AAGT,QAAO;;;;;;;AAQR,SAAS,YAAY,OAAqB;AACzC,KAAI,UAAU,QAAQ,UAAU,KAAA,EAC/B,QAAO;AAER,KAAI,OAAO,UAAU,SACpB,QAAO,WAAW,MAAM;AAEzB,KAAI,iBAAiB,KACpB,QAAO;AAER,KAAI,MAAM,QAAQ,MAAM,CACvB,QAAO,MAAM,IAAI,YAAY;AAE9B,KAAI,OAAO,UAAU,UAAU;EAC9B,MAAM,SAA8B,EAAE;AACtC,OAAK,MAAM,OAAO,OAAO,KAAK,MAAM,CACnC,QAAO,OAAO,YAAa,MAA8B,KAAK;AAE/D,SAAO;;AAER,QAAO;;AAGR,SAAgB,cAAiB,MAAyB;AACzD,KAAI;AACH,MAAI,OAAO,SAAS,UAAU;AAC7B,OAAI,SAAS,QAAQ,SAAS,KAAA,EAC7B,QAAO;AAER,UAAO,YAAY,KAAK;;AAEzB,SAAO,KAAK,MAAM,OAAO,GAAG,UAAU,WAAW,MAAM,CAAC;UAChD,GAAG;AACX,SAAO,MAAM,sBAAsB,EAAE,OAAO,GAAG,CAAC;AAChD,SAAO"}
@@ -2,7 +2,7 @@
2
2
  function capitalizeFirstLetter(str) {
3
3
  return str.charAt(0).toUpperCase() + str.slice(1);
4
4
  }
5
-
6
5
  //#endregion
7
6
  export { capitalizeFirstLetter };
7
+
8
8
  //# sourceMappingURL=string.mjs.map
@@ -27,7 +27,7 @@ function normalizePathname(requestUrl, basePath) {
27
27
  if (pathname.startsWith(basePath + "/")) return pathname.slice(basePath.length).replace(/\/+$/, "") || "/";
28
28
  return pathname;
29
29
  }
30
-
31
30
  //#endregion
32
31
  export { normalizePathname };
32
+
33
33
  //# sourceMappingURL=url.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-auth/core",
3
- "version": "1.5.5",
3
+ "version": "1.5.7-beta.1",
4
4
  "description": "The most comprehensive authentication framework for TypeScript.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -87,6 +87,11 @@
87
87
  "dev-source": "./src/oauth2/index.ts",
88
88
  "types": "./dist/oauth2/index.d.mts",
89
89
  "default": "./dist/oauth2/index.mjs"
90
+ },
91
+ "./instrumentation": {
92
+ "dev-source": "./src/instrumentation/index.ts",
93
+ "types": "./dist/instrumentation/index.d.mts",
94
+ "default": "./dist/instrumentation/index.mjs"
90
95
  }
91
96
  },
92
97
  "typesVersions": {
@@ -126,27 +131,35 @@
126
131
  ],
127
132
  "oauth2": [
128
133
  "dist/oauth2/index.d.mts"
134
+ ],
135
+ "instrumentation": [
136
+ "dist/instrumentation/index.d.mts"
129
137
  ]
130
138
  }
131
139
  },
132
140
  "dependencies": {
141
+ "@opentelemetry/semantic-conventions": "^1.39.0",
133
142
  "@standard-schema/spec": "^1.1.0",
134
143
  "zod": "^4.3.6"
135
144
  },
136
145
  "devDependencies": {
137
146
  "@better-auth/utils": "0.3.1",
138
147
  "@better-fetch/fetch": "1.1.21",
139
- "better-call": "1.3.2",
148
+ "@opentelemetry/api": "^1.9.0",
149
+ "@opentelemetry/sdk-trace-base": "^1.30.0",
150
+ "@opentelemetry/sdk-trace-node": "^1.30.0",
151
+ "better-call": "2.0.2",
140
152
  "@cloudflare/workers-types": "^4.20250121.0",
141
153
  "jose": "^6.1.3",
142
- "kysely": "^0.28.11",
154
+ "kysely": "^0.28.14",
143
155
  "nanostores": "^1.1.1",
144
- "tsdown": "0.21.0-beta.2"
156
+ "tsdown": "0.21.1"
145
157
  },
146
158
  "peerDependencies": {
147
159
  "@better-auth/utils": "0.3.1",
148
160
  "@better-fetch/fetch": "1.1.21",
149
- "better-call": "1.3.2",
161
+ "@opentelemetry/api": "^1.9.0",
162
+ "better-call": "2.0.2",
150
163
  "@cloudflare/workers-types": ">=4",
151
164
  "jose": "^6.1.0",
152
165
  "kysely": "^0.28.5",
package/src/api/index.ts CHANGED
@@ -1,7 +1,15 @@
1
1
  import type {
2
+ Endpoint,
2
3
  EndpointContext,
3
- EndpointOptions,
4
- StrictEndpoint,
4
+ EndpointMetadata,
5
+ EndpointRuntimeOptions,
6
+ HTTPMethod,
7
+ Middleware,
8
+ ResolveBodyInput,
9
+ ResolveErrorInput,
10
+ ResolveMetaInput,
11
+ ResolveQueryInput,
12
+ StandardSchemaV1,
5
13
  } from "better-call";
6
14
  import { createEndpoint, createMiddleware } from "better-call";
7
15
  import { runWithEndpointContext } from "../context";
@@ -33,47 +41,145 @@ export const createAuthMiddleware = createMiddleware.create({
33
41
 
34
42
  const use = [optionsMiddleware];
35
43
 
36
- type EndpointHandler<
37
- Path extends string,
38
- Options extends EndpointOptions,
39
- R,
40
- > = (context: EndpointContext<Path, Options, AuthContext>) => Promise<R>;
44
+ type BodyOption<M, B extends object | undefined = undefined> = M extends
45
+ | "GET"
46
+ | "HEAD"
47
+ | ("GET" | "HEAD")[]
48
+ ? { body?: never }
49
+ : { body?: B };
50
+
51
+ type AuthEndpointOptions<
52
+ Method extends HTTPMethod | HTTPMethod[] | "*",
53
+ BodySchema extends object | undefined,
54
+ QuerySchema extends object | undefined,
55
+ Use extends Middleware[],
56
+ ReqHeaders extends boolean,
57
+ ReqRequest extends boolean,
58
+ Meta extends EndpointMetadata | undefined,
59
+ ErrorSchema extends StandardSchemaV1 | undefined = undefined,
60
+ > = { method: Method } & BodyOption<Method, BodySchema> & {
61
+ query?: QuerySchema;
62
+ use?: [...Use];
63
+ requireHeaders?: ReqHeaders;
64
+ requireRequest?: ReqRequest;
65
+ error?: ErrorSchema;
66
+ cloneRequest?: boolean;
67
+ disableBody?: boolean;
68
+ metadata?: Meta;
69
+ [key: string]: any;
70
+ };
71
+
72
+ /**
73
+ * Normalize readonly tuples produced by `const` type parameters
74
+ * into mutable arrays so downstream `M extends Array<any>` checks work.
75
+ */
76
+ type NormalizeMethod<M> = M extends readonly (infer E)[] ? E[] : M;
41
77
 
78
+ // Path + options + handler overload
42
79
  export function createAuthEndpoint<
43
80
  Path extends string,
44
- Options extends EndpointOptions,
45
- R,
81
+ const Method extends HTTPMethod | HTTPMethod[] | "*",
82
+ BodySchema extends object | undefined = undefined,
83
+ QuerySchema extends object | undefined = undefined,
84
+ Use extends Middleware[] = [],
85
+ ReqHeaders extends boolean = false,
86
+ ReqRequest extends boolean = false,
87
+ R = unknown,
88
+ Meta extends EndpointMetadata | undefined = undefined,
89
+ ErrorSchema extends StandardSchemaV1 | undefined = undefined,
46
90
  >(
47
91
  path: Path,
48
- options: Options,
49
- handler: EndpointHandler<Path, Options, R>,
50
- ): StrictEndpoint<Path, Options, R>;
51
-
52
- export function createAuthEndpoint<
53
- Path extends string,
54
- Options extends EndpointOptions,
92
+ options: AuthEndpointOptions<
93
+ Method,
94
+ BodySchema,
95
+ QuerySchema,
96
+ Use,
97
+ ReqHeaders,
98
+ ReqRequest,
99
+ Meta,
100
+ ErrorSchema
101
+ >,
102
+ handler: (
103
+ ctx: EndpointContext<
104
+ Path,
105
+ Method,
106
+ BodySchema,
107
+ QuerySchema,
108
+ Use,
109
+ ReqHeaders,
110
+ ReqRequest,
111
+ AuthContext,
112
+ Meta
113
+ >,
114
+ ) => Promise<R>,
115
+ ): Endpoint<
116
+ Path,
117
+ NormalizeMethod<Method>,
118
+ ResolveBodyInput<BodySchema, Meta>,
119
+ ResolveQueryInput<QuerySchema, Meta>,
120
+ Use,
55
121
  R,
56
- >(
57
- options: Options,
58
- handler: EndpointHandler<Path, Options, R>,
59
- ): StrictEndpoint<Path, Options, R>;
122
+ ResolveMetaInput<Meta>,
123
+ ResolveErrorInput<ErrorSchema, Meta>
124
+ >;
60
125
 
126
+ // Options-only (virtual/path-less) overload
61
127
  export function createAuthEndpoint<
62
- Path extends string,
63
- Opts extends EndpointOptions,
64
- R,
128
+ const Method extends HTTPMethod | HTTPMethod[] | "*",
129
+ BodySchema extends object | undefined = undefined,
130
+ QuerySchema extends object | undefined = undefined,
131
+ Use extends Middleware[] = [],
132
+ ReqHeaders extends boolean = false,
133
+ ReqRequest extends boolean = false,
134
+ R = unknown,
135
+ Meta extends EndpointMetadata | undefined = undefined,
136
+ ErrorSchema extends StandardSchemaV1 | undefined = undefined,
65
137
  >(
66
- pathOrOptions: Path | Opts,
67
- handlerOrOptions: EndpointHandler<Path, Opts, R> | Opts,
138
+ options: AuthEndpointOptions<
139
+ Method,
140
+ BodySchema,
141
+ QuerySchema,
142
+ Use,
143
+ ReqHeaders,
144
+ ReqRequest,
145
+ Meta,
146
+ ErrorSchema
147
+ >,
148
+ handler: (
149
+ ctx: EndpointContext<
150
+ string,
151
+ Method,
152
+ BodySchema,
153
+ QuerySchema,
154
+ Use,
155
+ ReqHeaders,
156
+ ReqRequest,
157
+ AuthContext,
158
+ Meta
159
+ >,
160
+ ) => Promise<R>,
161
+ ): Endpoint<
162
+ string,
163
+ NormalizeMethod<Method>,
164
+ ResolveBodyInput<BodySchema, Meta>,
165
+ ResolveQueryInput<QuerySchema, Meta>,
166
+ Use,
167
+ R,
168
+ ResolveMetaInput<Meta>,
169
+ ResolveErrorInput<ErrorSchema, Meta>
170
+ >;
171
+
172
+ // Implementation
173
+ export function createAuthEndpoint(
174
+ pathOrOptions: any,
175
+ handlerOrOptions: any,
68
176
  handlerOrNever?: any,
69
177
  ) {
70
- const path: Path | undefined =
178
+ const path: string | undefined =
71
179
  typeof pathOrOptions === "string" ? pathOrOptions : undefined;
72
- const options: Opts =
73
- typeof handlerOrOptions === "object"
74
- ? handlerOrOptions
75
- : (pathOrOptions as Opts);
76
- const handler: EndpointHandler<Path, Opts, R> =
180
+ const options: EndpointRuntimeOptions =
181
+ typeof handlerOrOptions === "object" ? handlerOrOptions : pathOrOptions;
182
+ const handler =
77
183
  typeof handlerOrOptions === "function" ? handlerOrOptions : handlerOrNever;
78
184
 
79
185
  if (path) {
@@ -82,9 +188,9 @@ export function createAuthEndpoint<
82
188
  {
83
189
  ...options,
84
190
  use: [...(options?.use || []), ...use],
85
- },
191
+ } as any,
86
192
  // todo: prettify the code, we want to call `runWithEndpointContext` to top level
87
- async (ctx) => runWithEndpointContext(ctx as any, () => handler(ctx)),
193
+ async (ctx: any) => runWithEndpointContext(ctx, () => handler(ctx)),
88
194
  );
89
195
  }
90
196
 
@@ -92,15 +198,19 @@ export function createAuthEndpoint<
92
198
  {
93
199
  ...options,
94
200
  use: [...(options?.use || []), ...use],
95
- },
201
+ } as any,
96
202
  // todo: prettify the code, we want to call `runWithEndpointContext` to top level
97
- async (ctx) => runWithEndpointContext(ctx as any, () => handler(ctx)),
203
+ async (ctx: any) => runWithEndpointContext(ctx, () => handler(ctx)),
98
204
  );
99
205
  }
100
206
 
101
- export type AuthEndpoint<
102
- Path extends string,
103
- Opts extends EndpointOptions,
104
- R,
105
- > = ReturnType<typeof createAuthEndpoint<Path, Opts, R>>;
106
- export type AuthMiddleware = ReturnType<typeof createAuthMiddleware>;
207
+ export type AuthEndpoint = ReturnType<typeof createAuthEndpoint>;
208
+ /**
209
+ * The handler type for plugin hooks.
210
+ *
211
+ * Accepts both `Middleware` instances (from `createAuthMiddleware`)
212
+ * and plain async functions for better-call v1/v2 compatibility.
213
+ */
214
+ export type AuthMiddleware = (
215
+ inputContext: Record<string, any>,
216
+ ) => Promise<unknown>;
@@ -5,7 +5,8 @@ import type { AuthContext } from "../types";
5
5
  import { __getBetterAuthGlobal } from "./global";
6
6
 
7
7
  export type AuthEndpointContext = Partial<
8
- InputContext<string, any> & EndpointContext<string, any>
8
+ InputContext<string, any, any, any, any, any> &
9
+ EndpointContext<string, any, any, any, any, any, any, AuthContext>
9
10
  > & {
10
11
  context: AuthContext;
11
12
  };