better-auth 1.2.6-beta.7 → 1.2.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 (273) hide show
  1. package/dist/adapters/drizzle-adapter/index.cjs +186 -249
  2. package/dist/adapters/drizzle-adapter/index.d.cts +11 -49
  3. package/dist/adapters/drizzle-adapter/index.d.mts +11 -49
  4. package/dist/adapters/drizzle-adapter/index.d.ts +11 -49
  5. package/dist/adapters/drizzle-adapter/index.mjs +186 -249
  6. package/dist/adapters/index.cjs +26 -0
  7. package/dist/adapters/index.d.cts +17 -0
  8. package/dist/adapters/index.d.mts +17 -0
  9. package/dist/adapters/index.d.ts +17 -0
  10. package/dist/adapters/index.mjs +20 -0
  11. package/dist/adapters/kysely-adapter/index.cjs +7 -7
  12. package/dist/adapters/kysely-adapter/index.d.cts +17 -49
  13. package/dist/adapters/kysely-adapter/index.d.mts +17 -49
  14. package/dist/adapters/kysely-adapter/index.d.ts +17 -49
  15. package/dist/adapters/kysely-adapter/index.mjs +8 -8
  16. package/dist/adapters/memory-adapter/index.cjs +7 -8
  17. package/dist/adapters/memory-adapter/index.d.cts +9 -49
  18. package/dist/adapters/memory-adapter/index.d.mts +9 -49
  19. package/dist/adapters/memory-adapter/index.d.ts +9 -49
  20. package/dist/adapters/memory-adapter/index.mjs +8 -9
  21. package/dist/adapters/mongodb-adapter/index.cjs +2 -2
  22. package/dist/adapters/mongodb-adapter/index.d.cts +4 -4
  23. package/dist/adapters/mongodb-adapter/index.d.mts +4 -4
  24. package/dist/adapters/mongodb-adapter/index.d.ts +4 -4
  25. package/dist/adapters/mongodb-adapter/index.mjs +3 -3
  26. package/dist/adapters/prisma-adapter/index.cjs +130 -203
  27. package/dist/adapters/prisma-adapter/index.d.cts +17 -49
  28. package/dist/adapters/prisma-adapter/index.d.mts +17 -49
  29. package/dist/adapters/prisma-adapter/index.d.ts +17 -49
  30. package/dist/adapters/prisma-adapter/index.mjs +131 -204
  31. package/dist/adapters/test.cjs +710 -377
  32. package/dist/adapters/test.d.cts +64 -5
  33. package/dist/adapters/test.d.mts +64 -5
  34. package/dist/adapters/test.d.ts +64 -5
  35. package/dist/adapters/test.mjs +712 -380
  36. package/dist/api/index.cjs +61 -25
  37. package/dist/api/index.d.cts +3 -3
  38. package/dist/api/index.d.mts +3 -3
  39. package/dist/api/index.d.ts +3 -3
  40. package/dist/api/index.mjs +63 -27
  41. package/dist/client/index.d.cts +3 -3
  42. package/dist/client/index.d.mts +3 -3
  43. package/dist/client/index.d.ts +3 -3
  44. package/dist/client/plugins/index.cjs +13 -15
  45. package/dist/client/plugins/index.d.cts +80 -19
  46. package/dist/client/plugins/index.d.mts +80 -19
  47. package/dist/client/plugins/index.d.ts +80 -19
  48. package/dist/client/plugins/index.mjs +13 -16
  49. package/dist/client/react/index.cjs +4 -4
  50. package/dist/client/react/index.d.cts +3 -3
  51. package/dist/client/react/index.d.mts +3 -3
  52. package/dist/client/react/index.d.ts +3 -3
  53. package/dist/client/solid/index.d.cts +3 -3
  54. package/dist/client/solid/index.d.mts +3 -3
  55. package/dist/client/solid/index.d.ts +3 -3
  56. package/dist/client/svelte/index.d.cts +3 -3
  57. package/dist/client/svelte/index.d.mts +3 -3
  58. package/dist/client/svelte/index.d.ts +3 -3
  59. package/dist/client/vue/index.d.cts +3 -3
  60. package/dist/client/vue/index.d.mts +3 -3
  61. package/dist/client/vue/index.d.ts +3 -3
  62. package/dist/cookies/index.cjs +13 -2
  63. package/dist/cookies/index.d.cts +3 -3
  64. package/dist/cookies/index.d.mts +3 -3
  65. package/dist/cookies/index.d.ts +3 -3
  66. package/dist/cookies/index.mjs +13 -2
  67. package/dist/db/index.cjs +6 -5
  68. package/dist/db/index.d.cts +4 -4
  69. package/dist/db/index.d.mts +4 -4
  70. package/dist/db/index.d.ts +4 -4
  71. package/dist/db/index.mjs +7 -6
  72. package/dist/index.cjs +11 -7
  73. package/dist/index.d.cts +4 -4
  74. package/dist/index.d.mts +4 -4
  75. package/dist/index.d.ts +4 -4
  76. package/dist/index.mjs +14 -10
  77. package/dist/integrations/next-js.cjs +4 -5
  78. package/dist/integrations/next-js.d.cts +3 -3
  79. package/dist/integrations/next-js.d.mts +3 -3
  80. package/dist/integrations/next-js.d.ts +3 -3
  81. package/dist/integrations/next-js.mjs +5 -6
  82. package/dist/integrations/node.d.cts +3 -3
  83. package/dist/integrations/node.d.mts +3 -3
  84. package/dist/integrations/node.d.ts +3 -3
  85. package/dist/integrations/react-start.cjs +5 -6
  86. package/dist/integrations/react-start.d.cts +3 -3
  87. package/dist/integrations/react-start.d.mts +3 -3
  88. package/dist/integrations/react-start.d.ts +3 -3
  89. package/dist/integrations/react-start.mjs +6 -7
  90. package/dist/integrations/svelte-kit.d.cts +3 -3
  91. package/dist/integrations/svelte-kit.d.mts +3 -3
  92. package/dist/integrations/svelte-kit.d.ts +3 -3
  93. package/dist/oauth2/index.d.cts +5 -5
  94. package/dist/oauth2/index.d.mts +5 -5
  95. package/dist/oauth2/index.d.ts +5 -5
  96. package/dist/plugins/access/index.d.cts +1 -1
  97. package/dist/plugins/access/index.d.mts +1 -1
  98. package/dist/plugins/access/index.d.ts +1 -1
  99. package/dist/plugins/admin/access/index.d.cts +1 -1
  100. package/dist/plugins/admin/access/index.d.mts +1 -1
  101. package/dist/plugins/admin/access/index.d.ts +1 -1
  102. package/dist/plugins/admin/index.cjs +4 -4
  103. package/dist/plugins/admin/index.d.cts +74 -14
  104. package/dist/plugins/admin/index.d.mts +74 -14
  105. package/dist/plugins/admin/index.d.ts +74 -14
  106. package/dist/plugins/admin/index.mjs +5 -5
  107. package/dist/plugins/anonymous/index.cjs +4 -5
  108. package/dist/plugins/anonymous/index.d.cts +3 -3
  109. package/dist/plugins/anonymous/index.d.mts +3 -3
  110. package/dist/plugins/anonymous/index.d.ts +3 -3
  111. package/dist/plugins/anonymous/index.mjs +5 -6
  112. package/dist/plugins/bearer/index.cjs +2 -2
  113. package/dist/plugins/bearer/index.d.cts +3 -3
  114. package/dist/plugins/bearer/index.d.mts +3 -3
  115. package/dist/plugins/bearer/index.d.ts +3 -3
  116. package/dist/plugins/bearer/index.mjs +3 -3
  117. package/dist/plugins/captcha/index.cjs +110 -45
  118. package/dist/plugins/captcha/index.d.cts +26 -6
  119. package/dist/plugins/captcha/index.d.mts +26 -6
  120. package/dist/plugins/captcha/index.d.ts +26 -6
  121. package/dist/plugins/captcha/index.mjs +110 -45
  122. package/dist/plugins/custom-session/index.cjs +24 -5
  123. package/dist/plugins/custom-session/index.d.cts +25 -6
  124. package/dist/plugins/custom-session/index.d.mts +25 -6
  125. package/dist/plugins/custom-session/index.d.ts +25 -6
  126. package/dist/plugins/custom-session/index.mjs +25 -6
  127. package/dist/plugins/email-otp/index.cjs +96 -30
  128. package/dist/plugins/email-otp/index.d.cts +33 -10
  129. package/dist/plugins/email-otp/index.d.mts +33 -10
  130. package/dist/plugins/email-otp/index.d.ts +33 -10
  131. package/dist/plugins/email-otp/index.mjs +97 -31
  132. package/dist/plugins/generic-oauth/index.cjs +81 -20
  133. package/dist/plugins/generic-oauth/index.d.cts +46 -3
  134. package/dist/plugins/generic-oauth/index.d.mts +46 -3
  135. package/dist/plugins/generic-oauth/index.d.ts +46 -3
  136. package/dist/plugins/generic-oauth/index.mjs +82 -21
  137. package/dist/plugins/haveibeenpwned/index.cjs +98 -0
  138. package/dist/plugins/haveibeenpwned/index.d.cts +36 -0
  139. package/dist/plugins/haveibeenpwned/index.d.mts +36 -0
  140. package/dist/plugins/haveibeenpwned/index.d.ts +36 -0
  141. package/dist/plugins/haveibeenpwned/index.mjs +96 -0
  142. package/dist/plugins/index.cjs +583 -19
  143. package/dist/plugins/index.d.cts +7 -5
  144. package/dist/plugins/index.d.mts +7 -5
  145. package/dist/plugins/index.d.ts +7 -5
  146. package/dist/plugins/index.mjs +583 -21
  147. package/dist/plugins/jwt/index.cjs +45 -21
  148. package/dist/plugins/jwt/index.d.cts +52 -6
  149. package/dist/plugins/jwt/index.d.mts +52 -6
  150. package/dist/plugins/jwt/index.d.ts +52 -6
  151. package/dist/plugins/jwt/index.mjs +46 -22
  152. package/dist/plugins/magic-link/index.cjs +3 -3
  153. package/dist/plugins/magic-link/index.mjs +4 -4
  154. package/dist/plugins/multi-session/index.cjs +3 -3
  155. package/dist/plugins/multi-session/index.d.cts +3 -3
  156. package/dist/plugins/multi-session/index.d.mts +3 -3
  157. package/dist/plugins/multi-session/index.d.ts +3 -3
  158. package/dist/plugins/multi-session/index.mjs +4 -4
  159. package/dist/plugins/oauth-proxy/index.cjs +4 -4
  160. package/dist/plugins/oauth-proxy/index.d.cts +3 -3
  161. package/dist/plugins/oauth-proxy/index.d.mts +3 -3
  162. package/dist/plugins/oauth-proxy/index.d.ts +3 -3
  163. package/dist/plugins/oauth-proxy/index.mjs +5 -5
  164. package/dist/plugins/oidc-provider/index.cjs +227 -8
  165. package/dist/plugins/oidc-provider/index.d.cts +215 -3
  166. package/dist/plugins/oidc-provider/index.d.mts +215 -3
  167. package/dist/plugins/oidc-provider/index.d.ts +215 -3
  168. package/dist/plugins/oidc-provider/index.mjs +228 -9
  169. package/dist/plugins/one-tap/index.cjs +5 -5
  170. package/dist/plugins/one-tap/index.mjs +6 -6
  171. package/dist/plugins/one-time-token/index.cjs +119 -0
  172. package/dist/plugins/one-time-token/index.d.cts +134 -0
  173. package/dist/plugins/one-time-token/index.d.mts +134 -0
  174. package/dist/plugins/one-time-token/index.d.ts +134 -0
  175. package/dist/plugins/one-time-token/index.mjs +117 -0
  176. package/dist/plugins/open-api/index.cjs +3 -3
  177. package/dist/plugins/open-api/index.d.cts +3 -3
  178. package/dist/plugins/open-api/index.d.mts +3 -3
  179. package/dist/plugins/open-api/index.d.ts +3 -3
  180. package/dist/plugins/open-api/index.mjs +4 -4
  181. package/dist/plugins/organization/access/index.d.cts +1 -1
  182. package/dist/plugins/organization/access/index.d.mts +1 -1
  183. package/dist/plugins/organization/access/index.d.ts +1 -1
  184. package/dist/plugins/organization/index.cjs +4 -4
  185. package/dist/plugins/organization/index.d.cts +708 -55
  186. package/dist/plugins/organization/index.d.mts +708 -55
  187. package/dist/plugins/organization/index.d.ts +708 -55
  188. package/dist/plugins/organization/index.mjs +5 -5
  189. package/dist/plugins/passkey/index.cjs +82 -8
  190. package/dist/plugins/passkey/index.d.cts +72 -3
  191. package/dist/plugins/passkey/index.d.mts +72 -3
  192. package/dist/plugins/passkey/index.d.ts +72 -3
  193. package/dist/plugins/passkey/index.mjs +83 -9
  194. package/dist/plugins/phone-number/index.cjs +194 -26
  195. package/dist/plugins/phone-number/index.d.cts +132 -8
  196. package/dist/plugins/phone-number/index.d.mts +132 -8
  197. package/dist/plugins/phone-number/index.d.ts +132 -8
  198. package/dist/plugins/phone-number/index.mjs +195 -27
  199. package/dist/plugins/sso/index.cjs +190 -7
  200. package/dist/plugins/sso/index.d.cts +181 -15
  201. package/dist/plugins/sso/index.d.mts +181 -15
  202. package/dist/plugins/sso/index.d.ts +181 -15
  203. package/dist/plugins/sso/index.mjs +191 -8
  204. package/dist/plugins/two-factor/index.cjs +443 -92
  205. package/dist/plugins/two-factor/index.d.cts +230 -396
  206. package/dist/plugins/two-factor/index.d.mts +230 -396
  207. package/dist/plugins/two-factor/index.d.ts +230 -396
  208. package/dist/plugins/two-factor/index.mjs +431 -80
  209. package/dist/plugins/username/index.cjs +34 -31
  210. package/dist/plugins/username/index.d.cts +15 -12
  211. package/dist/plugins/username/index.d.mts +15 -12
  212. package/dist/plugins/username/index.d.ts +15 -12
  213. package/dist/plugins/username/index.mjs +35 -32
  214. package/dist/shared/better-auth.1DR6suCQ.mjs +307 -0
  215. package/dist/shared/{better-auth.BSsp73pg.cjs → better-auth.B7cZ2juS.cjs} +15 -14
  216. package/dist/shared/{better-auth.bKwabe3I.d.mts → better-auth.B88xucNq.d.mts} +529 -39
  217. package/dist/shared/{better-auth.CApEjVDP.cjs → better-auth.BW8BpneG.cjs} +4 -1
  218. package/dist/shared/{better-auth.BiQsvaIP.d.cts → better-auth.BcU1Kjyq.d.cts} +2051 -518
  219. package/dist/shared/better-auth.BfG24BjZ.cjs +118 -0
  220. package/dist/shared/{better-auth.A3TjrU8G.mjs → better-auth.Bk5IMdhM.mjs} +32 -12
  221. package/dist/shared/{better-auth.D9VnBkRI.mjs → better-auth.Bm9HxIzE.mjs} +47 -24
  222. package/dist/shared/{better-auth.BRf6Iynu.d.ts → better-auth.Bwc-6kOr.d.ts} +1 -1
  223. package/dist/shared/{better-auth.D-oLmHIj.d.mts → better-auth.CA2hFK4N.d.ts} +2051 -518
  224. package/dist/shared/{better-auth.Dmhe30iW.d.mts → better-auth.CGukGrxT.d.cts} +1 -1
  225. package/dist/shared/{better-auth.CsSpq0zL.cjs → better-auth.CHUzBidy.cjs} +46 -23
  226. package/dist/shared/{better-auth.DWRligF8.d.cts → better-auth.CT9J6rD-.d.cts} +539 -7
  227. package/dist/shared/better-auth.CVCo5Z2T.cjs +310 -0
  228. package/dist/shared/{better-auth.D4jH-sJA.mjs → better-auth.CWwVo_61.mjs} +458 -118
  229. package/dist/shared/{better-auth.Bi8FQwDD.d.cts → better-auth.CYegVoq1.d.cts} +1 -1
  230. package/dist/shared/{better-auth.Bi8FQwDD.d.mts → better-auth.CYegVoq1.d.mts} +1 -1
  231. package/dist/shared/{better-auth.Bi8FQwDD.d.ts → better-auth.CYegVoq1.d.ts} +1 -1
  232. package/dist/shared/{better-auth.CepcSj5H.mjs → better-auth.Cc72UxUH.mjs} +1 -2
  233. package/dist/shared/{better-auth.BWp5dztg.d.ts → better-auth.CmN4mlPh.d.ts} +539 -7
  234. package/dist/shared/{better-auth.DH3YjMQH.mjs → better-auth.Cqykj82J.mjs} +1 -1
  235. package/dist/shared/{better-auth.wcdMj2cT.d.mts → better-auth.DIt2e3lu.d.mts} +539 -7
  236. package/dist/shared/{better-auth.BANAxdkL.d.ts → better-auth.DNTAFSt1.d.ts} +529 -39
  237. package/dist/shared/{better-auth.DU2QNVc_.d.ts → better-auth.DQ7OSJbI.d.mts} +2051 -518
  238. package/dist/shared/{better-auth.DLTzKoOS.cjs → better-auth.DSVbLSt7.cjs} +4 -1
  239. package/dist/shared/{better-auth.B2Fw1vhH.d.cts → better-auth.DTiSPWEk.d.cts} +529 -39
  240. package/dist/shared/better-auth.DURsStt9.mjs +116 -0
  241. package/dist/shared/{better-auth.BIjcZ_vt.cjs → better-auth.DYoLD99C.cjs} +31 -11
  242. package/dist/shared/{better-auth.CV1L7TPV.cjs → better-auth.D_ZIX1O8.cjs} +317 -47
  243. package/dist/shared/{better-auth.C5H9XEzZ.cjs → better-auth.DcWKCjjf.cjs} +1 -2
  244. package/dist/shared/{better-auth.BDYXUcLv.cjs → better-auth.Dg0siV5C.cjs} +457 -117
  245. package/dist/shared/better-auth.DjryM8pE.cjs +760 -0
  246. package/dist/shared/{better-auth.DPBQN9Fs.mjs → better-auth.Dn_Ms1Uf.mjs} +318 -48
  247. package/dist/shared/{better-auth.DiG4KL2x.mjs → better-auth.OuYYTHC7.mjs} +4 -1
  248. package/dist/shared/{better-auth.DtC8i3pf.d.cts → better-auth.S1jimRbX.d.mts} +1 -1
  249. package/dist/shared/better-auth.SPmq4a4z.d.mts +344 -0
  250. package/dist/shared/{better-auth.cOCrlspr.mjs → better-auth.bkwPl2G4.mjs} +4 -1
  251. package/dist/shared/better-auth.cp2rC2iM.d.ts +344 -0
  252. package/dist/shared/better-auth.eVy4DZvP.d.cts +344 -0
  253. package/dist/shared/{better-auth.BrOpzmqo.mjs → better-auth.iKoUsdFE.mjs} +15 -14
  254. package/dist/shared/better-auth.rSYJCd3o.mjs +758 -0
  255. package/dist/social-providers/index.cjs +75 -3
  256. package/dist/social-providers/index.d.cts +2 -2
  257. package/dist/social-providers/index.d.mts +2 -2
  258. package/dist/social-providers/index.d.ts +2 -2
  259. package/dist/social-providers/index.mjs +77 -6
  260. package/dist/types/index.d.cts +4 -4
  261. package/dist/types/index.d.mts +4 -4
  262. package/dist/types/index.d.ts +4 -4
  263. package/package.json +42 -5
  264. package/dist/chunks/server.cjs +0 -905
  265. package/dist/chunks/server.mjs +0 -895
  266. package/dist/shared/better-auth.BcoSd9tC.mjs +0 -10
  267. package/dist/shared/better-auth.BnRFp-t0.mjs +0 -405
  268. package/dist/shared/better-auth.C1-vpKly.cjs +0 -12
  269. package/dist/shared/better-auth.ClTSOgiD.mjs +0 -140
  270. package/dist/shared/better-auth.DC8JQbiE.mjs +0 -173
  271. package/dist/shared/better-auth.DWHWPllD.cjs +0 -175
  272. package/dist/shared/better-auth.DqLjzBlO.cjs +0 -408
  273. package/dist/shared/better-auth.m575EIBC.cjs +0 -144
@@ -1,8 +1,8 @@
1
1
  import * as better_call from 'better-call';
2
- import { H as HookEndpointContext } from '../../shared/better-auth.DU2QNVc_.js';
3
- import '../../shared/better-auth.Bi8FQwDD.js';
2
+ import { H as HookEndpointContext } from '../../shared/better-auth.CA2hFK4N.js';
3
+ import '../../shared/better-auth.CYegVoq1.js';
4
4
  import 'zod';
5
- import '../../shared/better-auth.BANAxdkL.js';
5
+ import '../../shared/better-auth.DNTAFSt1.js';
6
6
  import 'jose';
7
7
  import 'kysely';
8
8
  import 'better-sqlite3';
@@ -3,10 +3,10 @@ import '../../shared/better-auth.8zoxzg-F.mjs';
3
3
  import '@better-auth/utils/base64';
4
4
  import { createHMAC } from '@better-auth/utils/hmac';
5
5
  import { parseSetCookieHeader } from '../../cookies/index.mjs';
6
- import { c as createAuthMiddleware } from '../../shared/better-auth.D4jH-sJA.mjs';
6
+ import { c as createAuthMiddleware } from '../../shared/better-auth.CWwVo_61.mjs';
7
7
  import 'zod';
8
- import '../../shared/better-auth.CepcSj5H.mjs';
9
- import '../../shared/better-auth.DH3YjMQH.mjs';
8
+ import '../../shared/better-auth.Cc72UxUH.mjs';
9
+ import '../../shared/better-auth.Cqykj82J.mjs';
10
10
  import 'defu';
11
11
  import '../../shared/better-auth.DdzSJf-n.mjs';
12
12
  import '../../shared/better-auth.CW6D9eSx.mjs';
@@ -2,22 +2,31 @@
2
2
 
3
3
  const fetch = require('@better-fetch/fetch');
4
4
 
5
- const defaultEndpoints = ["/sign-up", "/sign-in", "/forget-password"];
5
+ const defaultEndpoints = [
6
+ "/sign-up/email",
7
+ "/sign-in/email",
8
+ "/forget-password"
9
+ ];
6
10
  const Providers = {
7
11
  CLOUDFLARE_TURNSTILE: "cloudflare-turnstile",
8
- GOOGLE_RECAPTCHA: "google-recaptcha"
12
+ GOOGLE_RECAPTCHA: "google-recaptcha",
13
+ HCAPTCHA: "hcaptcha"
9
14
  };
10
15
  const siteVerifyMap = {
11
16
  [Providers.CLOUDFLARE_TURNSTILE]: "https://challenges.cloudflare.com/turnstile/v0/siteverify",
12
- [Providers.GOOGLE_RECAPTCHA]: "https://www.google.com/recaptcha/api/siteverify"
17
+ [Providers.GOOGLE_RECAPTCHA]: "https://www.google.com/recaptcha/api/siteverify",
18
+ [Providers.HCAPTCHA]: "https://api.hcaptcha.com/siteverify"
13
19
  };
14
20
 
15
- const CAPTCHA_ERROR_CODES = {
16
- MISSING_RESPONSE: "Missing CAPTCHA response",
17
- SERVICE_UNAVAILABLE: "CAPTCHA service unavailable",
21
+ const EXTERNAL_ERROR_CODES = {
18
22
  VERIFICATION_FAILED: "Captcha verification failed",
23
+ MISSING_RESPONSE: "Missing CAPTCHA response",
19
24
  UNKNOWN_ERROR: "Something went wrong"
20
25
  };
26
+ const INTERNAL_ERROR_CODES = {
27
+ MISSING_SECRET_KEY: "Missing secret key",
28
+ SERVICE_UNAVAILABLE: "CAPTCHA service unavailable"
29
+ };
21
30
 
22
31
  const middlewareResponse = ({ message, status }) => ({
23
32
  response: new Response(
@@ -33,59 +42,100 @@ const middlewareResponse = ({ message, status }) => ({
33
42
  const cloudflareTurnstile = async ({
34
43
  siteVerifyURL,
35
44
  captchaResponse,
36
- secretKey
45
+ secretKey,
46
+ remoteIP
37
47
  }) => {
38
- const response = await fetch.betterFetch(
39
- siteVerifyURL,
40
- {
41
- method: "POST",
42
- headers: { "Content-Type": "application/json" },
43
- body: JSON.stringify({
44
- secret: secretKey,
45
- response: captchaResponse
46
- })
47
- }
48
- );
48
+ const response = await fetch.betterFetch(siteVerifyURL, {
49
+ method: "POST",
50
+ headers: { "Content-Type": "application/json" },
51
+ body: JSON.stringify({
52
+ secret: secretKey,
53
+ response: captchaResponse,
54
+ ...remoteIP && { remoteip: remoteIP }
55
+ })
56
+ });
49
57
  if (!response.data || response.error) {
50
- return middlewareResponse({
51
- message: CAPTCHA_ERROR_CODES.SERVICE_UNAVAILABLE,
52
- status: 503
53
- });
58
+ throw new Error(INTERNAL_ERROR_CODES.SERVICE_UNAVAILABLE);
54
59
  }
55
60
  if (!response.data.success) {
56
61
  return middlewareResponse({
57
- message: CAPTCHA_ERROR_CODES.VERIFICATION_FAILED,
62
+ message: EXTERNAL_ERROR_CODES.VERIFICATION_FAILED,
58
63
  status: 403
59
64
  });
60
65
  }
61
66
  return void 0;
62
67
  };
63
68
 
64
- const googleReCAPTCHA = async ({
69
+ const encodeToURLParams = (obj) => {
70
+ if (typeof obj !== "object" || obj === null || Array.isArray(obj)) {
71
+ throw new Error("Input must be a non-null object.");
72
+ }
73
+ const params = new URLSearchParams();
74
+ for (const [key, value] of Object.entries(obj)) {
75
+ if (value !== void 0 && value !== null) {
76
+ params.append(key, String(value));
77
+ }
78
+ }
79
+ return params.toString();
80
+ };
81
+
82
+ const isV3 = (response) => {
83
+ return "score" in response && typeof response.score === "number";
84
+ };
85
+ const googleRecaptcha = async ({
65
86
  siteVerifyURL,
66
87
  captchaResponse,
67
- secretKey
88
+ secretKey,
89
+ minScore = 0.5,
90
+ remoteIP
68
91
  }) => {
69
92
  const response = await fetch.betterFetch(
70
93
  siteVerifyURL,
71
94
  {
72
95
  method: "POST",
73
- headers: { "Content-Type": "application/json" },
74
- body: JSON.stringify({
96
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
97
+ body: encodeToURLParams({
75
98
  secret: secretKey,
76
- response: captchaResponse
99
+ response: captchaResponse,
100
+ ...remoteIP && { remoteip: remoteIP }
77
101
  })
78
102
  }
79
103
  );
80
104
  if (!response.data || response.error) {
105
+ throw new Error(INTERNAL_ERROR_CODES.SERVICE_UNAVAILABLE);
106
+ }
107
+ if (!response.data.success || isV3(response.data) && response.data.score < minScore) {
81
108
  return middlewareResponse({
82
- message: CAPTCHA_ERROR_CODES.SERVICE_UNAVAILABLE,
83
- status: 503
109
+ message: EXTERNAL_ERROR_CODES.VERIFICATION_FAILED,
110
+ status: 403
84
111
  });
85
112
  }
113
+ return void 0;
114
+ };
115
+
116
+ const hCaptcha = async ({
117
+ siteVerifyURL,
118
+ captchaResponse,
119
+ secretKey,
120
+ siteKey,
121
+ remoteIP
122
+ }) => {
123
+ const response = await fetch.betterFetch(siteVerifyURL, {
124
+ method: "POST",
125
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
126
+ body: encodeToURLParams({
127
+ secret: secretKey,
128
+ response: captchaResponse,
129
+ ...siteKey && { sitekey: siteKey },
130
+ ...remoteIP && { remoteip: remoteIP }
131
+ })
132
+ });
133
+ if (!response.data || response.error) {
134
+ throw new Error(INTERNAL_ERROR_CODES.SERVICE_UNAVAILABLE);
135
+ }
86
136
  if (!response.data.success) {
87
137
  return middlewareResponse({
88
- message: CAPTCHA_ERROR_CODES.VERIFICATION_FAILED,
138
+ message: EXTERNAL_ERROR_CODES.VERIFICATION_FAILED,
89
139
  status: 403
90
140
  });
91
141
  }
@@ -94,37 +144,52 @@ const googleReCAPTCHA = async ({
94
144
 
95
145
  const captcha = (options) => ({
96
146
  id: "captcha",
97
- onRequest: async (request) => {
147
+ onRequest: async (request, ctx) => {
98
148
  try {
99
- if (request.method !== "POST") return void 0;
100
149
  const endpoints = options.endpoints?.length ? options.endpoints : defaultEndpoints;
101
150
  if (!endpoints.some((endpoint) => request.url.includes(endpoint)))
102
- return;
151
+ return void 0;
152
+ if (!options.secretKey) {
153
+ throw new Error(INTERNAL_ERROR_CODES.MISSING_SECRET_KEY);
154
+ }
103
155
  const captchaResponse = request.headers.get("x-captcha-response");
156
+ const remoteUserIP = request.headers.get("x-captcha-user-remote-ip") ?? void 0;
104
157
  if (!captchaResponse) {
105
158
  return middlewareResponse({
106
- message: CAPTCHA_ERROR_CODES.MISSING_RESPONSE,
159
+ message: EXTERNAL_ERROR_CODES.MISSING_RESPONSE,
107
160
  status: 400
108
161
  });
109
162
  }
110
163
  const siteVerifyURL = options.siteVerifyURLOverride || siteVerifyMap[options.provider];
164
+ const handlerParams = {
165
+ siteVerifyURL,
166
+ captchaResponse,
167
+ secretKey: options.secretKey,
168
+ remoteIP: remoteUserIP
169
+ };
111
170
  if (options.provider === Providers.CLOUDFLARE_TURNSTILE) {
112
- return await cloudflareTurnstile({
113
- secretKey: options.secretKey,
114
- captchaResponse,
115
- siteVerifyURL
116
- });
171
+ return await cloudflareTurnstile(handlerParams);
117
172
  }
118
173
  if (options.provider === Providers.GOOGLE_RECAPTCHA) {
119
- return await googleReCAPTCHA({
120
- secretKey: options.secretKey,
121
- captchaResponse,
122
- siteVerifyURL
174
+ return await googleRecaptcha({
175
+ ...handlerParams,
176
+ minScore: options.minScore
177
+ });
178
+ }
179
+ if (options.provider === Providers.HCAPTCHA) {
180
+ return await hCaptcha({
181
+ ...handlerParams,
182
+ siteKey: options.siteKey
123
183
  });
124
184
  }
125
185
  } catch (_error) {
186
+ const errorMessage = _error instanceof Error ? _error.message : void 0;
187
+ ctx.logger.error(errorMessage ?? "Unknown error", {
188
+ endpoint: request.url,
189
+ message: _error
190
+ });
126
191
  return middlewareResponse({
127
- message: CAPTCHA_ERROR_CODES.UNKNOWN_ERROR,
192
+ message: EXTERNAL_ERROR_CODES.UNKNOWN_ERROR,
128
193
  status: 500
129
194
  });
130
195
  }
@@ -1,21 +1,41 @@
1
+ import { l as AuthContext } from '../../shared/better-auth.BcU1Kjyq.cjs';
2
+ import '../../shared/better-auth.CYegVoq1.cjs';
3
+ import 'zod';
4
+ import '../../shared/better-auth.DTiSPWEk.cjs';
5
+ import 'jose';
6
+ import 'kysely';
7
+ import 'better-call';
8
+ import 'better-sqlite3';
9
+
1
10
  declare const Providers: {
2
11
  readonly CLOUDFLARE_TURNSTILE: "cloudflare-turnstile";
3
12
  readonly GOOGLE_RECAPTCHA: "google-recaptcha";
13
+ readonly HCAPTCHA: "hcaptcha";
4
14
  };
5
15
 
6
- type Provider = (typeof Providers)[keyof typeof Providers];
7
-
8
- interface CaptchaOptions {
9
- provider: Provider;
16
+ interface BaseCaptchaOptions {
10
17
  secretKey: string;
11
18
  endpoints?: string[];
12
19
  siteVerifyURLOverride?: string;
13
20
  }
21
+ interface GoogleRecaptchaOptions extends BaseCaptchaOptions {
22
+ provider: typeof Providers.GOOGLE_RECAPTCHA;
23
+ minScore?: number;
24
+ }
25
+ interface CloudflareTurnstileOptions extends BaseCaptchaOptions {
26
+ provider: typeof Providers.CLOUDFLARE_TURNSTILE;
27
+ }
28
+ interface HCaptchaOptions extends BaseCaptchaOptions {
29
+ provider: typeof Providers.HCAPTCHA;
30
+ siteKey?: string;
31
+ }
32
+ type CaptchaOptions = GoogleRecaptchaOptions | CloudflareTurnstileOptions | HCaptchaOptions;
33
+
14
34
  declare const captcha: (options: CaptchaOptions) => {
15
35
  id: "captcha";
16
- onRequest: (request: Request) => Promise<{
36
+ onRequest: (request: Request, ctx: AuthContext) => Promise<{
17
37
  response: Response;
18
38
  } | undefined>;
19
39
  };
20
40
 
21
- export { type CaptchaOptions, captcha };
41
+ export { captcha };
@@ -1,21 +1,41 @@
1
+ import { l as AuthContext } from '../../shared/better-auth.DQ7OSJbI.mjs';
2
+ import '../../shared/better-auth.CYegVoq1.mjs';
3
+ import 'zod';
4
+ import '../../shared/better-auth.B88xucNq.mjs';
5
+ import 'jose';
6
+ import 'kysely';
7
+ import 'better-call';
8
+ import 'better-sqlite3';
9
+
1
10
  declare const Providers: {
2
11
  readonly CLOUDFLARE_TURNSTILE: "cloudflare-turnstile";
3
12
  readonly GOOGLE_RECAPTCHA: "google-recaptcha";
13
+ readonly HCAPTCHA: "hcaptcha";
4
14
  };
5
15
 
6
- type Provider = (typeof Providers)[keyof typeof Providers];
7
-
8
- interface CaptchaOptions {
9
- provider: Provider;
16
+ interface BaseCaptchaOptions {
10
17
  secretKey: string;
11
18
  endpoints?: string[];
12
19
  siteVerifyURLOverride?: string;
13
20
  }
21
+ interface GoogleRecaptchaOptions extends BaseCaptchaOptions {
22
+ provider: typeof Providers.GOOGLE_RECAPTCHA;
23
+ minScore?: number;
24
+ }
25
+ interface CloudflareTurnstileOptions extends BaseCaptchaOptions {
26
+ provider: typeof Providers.CLOUDFLARE_TURNSTILE;
27
+ }
28
+ interface HCaptchaOptions extends BaseCaptchaOptions {
29
+ provider: typeof Providers.HCAPTCHA;
30
+ siteKey?: string;
31
+ }
32
+ type CaptchaOptions = GoogleRecaptchaOptions | CloudflareTurnstileOptions | HCaptchaOptions;
33
+
14
34
  declare const captcha: (options: CaptchaOptions) => {
15
35
  id: "captcha";
16
- onRequest: (request: Request) => Promise<{
36
+ onRequest: (request: Request, ctx: AuthContext) => Promise<{
17
37
  response: Response;
18
38
  } | undefined>;
19
39
  };
20
40
 
21
- export { type CaptchaOptions, captcha };
41
+ export { captcha };
@@ -1,21 +1,41 @@
1
+ import { l as AuthContext } from '../../shared/better-auth.CA2hFK4N.js';
2
+ import '../../shared/better-auth.CYegVoq1.js';
3
+ import 'zod';
4
+ import '../../shared/better-auth.DNTAFSt1.js';
5
+ import 'jose';
6
+ import 'kysely';
7
+ import 'better-call';
8
+ import 'better-sqlite3';
9
+
1
10
  declare const Providers: {
2
11
  readonly CLOUDFLARE_TURNSTILE: "cloudflare-turnstile";
3
12
  readonly GOOGLE_RECAPTCHA: "google-recaptcha";
13
+ readonly HCAPTCHA: "hcaptcha";
4
14
  };
5
15
 
6
- type Provider = (typeof Providers)[keyof typeof Providers];
7
-
8
- interface CaptchaOptions {
9
- provider: Provider;
16
+ interface BaseCaptchaOptions {
10
17
  secretKey: string;
11
18
  endpoints?: string[];
12
19
  siteVerifyURLOverride?: string;
13
20
  }
21
+ interface GoogleRecaptchaOptions extends BaseCaptchaOptions {
22
+ provider: typeof Providers.GOOGLE_RECAPTCHA;
23
+ minScore?: number;
24
+ }
25
+ interface CloudflareTurnstileOptions extends BaseCaptchaOptions {
26
+ provider: typeof Providers.CLOUDFLARE_TURNSTILE;
27
+ }
28
+ interface HCaptchaOptions extends BaseCaptchaOptions {
29
+ provider: typeof Providers.HCAPTCHA;
30
+ siteKey?: string;
31
+ }
32
+ type CaptchaOptions = GoogleRecaptchaOptions | CloudflareTurnstileOptions | HCaptchaOptions;
33
+
14
34
  declare const captcha: (options: CaptchaOptions) => {
15
35
  id: "captcha";
16
- onRequest: (request: Request) => Promise<{
36
+ onRequest: (request: Request, ctx: AuthContext) => Promise<{
17
37
  response: Response;
18
38
  } | undefined>;
19
39
  };
20
40
 
21
- export { type CaptchaOptions, captcha };
41
+ export { captcha };
@@ -1,21 +1,30 @@
1
1
  import { betterFetch } from '@better-fetch/fetch';
2
2
 
3
- const defaultEndpoints = ["/sign-up", "/sign-in", "/forget-password"];
3
+ const defaultEndpoints = [
4
+ "/sign-up/email",
5
+ "/sign-in/email",
6
+ "/forget-password"
7
+ ];
4
8
  const Providers = {
5
9
  CLOUDFLARE_TURNSTILE: "cloudflare-turnstile",
6
- GOOGLE_RECAPTCHA: "google-recaptcha"
10
+ GOOGLE_RECAPTCHA: "google-recaptcha",
11
+ HCAPTCHA: "hcaptcha"
7
12
  };
8
13
  const siteVerifyMap = {
9
14
  [Providers.CLOUDFLARE_TURNSTILE]: "https://challenges.cloudflare.com/turnstile/v0/siteverify",
10
- [Providers.GOOGLE_RECAPTCHA]: "https://www.google.com/recaptcha/api/siteverify"
15
+ [Providers.GOOGLE_RECAPTCHA]: "https://www.google.com/recaptcha/api/siteverify",
16
+ [Providers.HCAPTCHA]: "https://api.hcaptcha.com/siteverify"
11
17
  };
12
18
 
13
- const CAPTCHA_ERROR_CODES = {
14
- MISSING_RESPONSE: "Missing CAPTCHA response",
15
- SERVICE_UNAVAILABLE: "CAPTCHA service unavailable",
19
+ const EXTERNAL_ERROR_CODES = {
16
20
  VERIFICATION_FAILED: "Captcha verification failed",
21
+ MISSING_RESPONSE: "Missing CAPTCHA response",
17
22
  UNKNOWN_ERROR: "Something went wrong"
18
23
  };
24
+ const INTERNAL_ERROR_CODES = {
25
+ MISSING_SECRET_KEY: "Missing secret key",
26
+ SERVICE_UNAVAILABLE: "CAPTCHA service unavailable"
27
+ };
19
28
 
20
29
  const middlewareResponse = ({ message, status }) => ({
21
30
  response: new Response(
@@ -31,59 +40,100 @@ const middlewareResponse = ({ message, status }) => ({
31
40
  const cloudflareTurnstile = async ({
32
41
  siteVerifyURL,
33
42
  captchaResponse,
34
- secretKey
43
+ secretKey,
44
+ remoteIP
35
45
  }) => {
36
- const response = await betterFetch(
37
- siteVerifyURL,
38
- {
39
- method: "POST",
40
- headers: { "Content-Type": "application/json" },
41
- body: JSON.stringify({
42
- secret: secretKey,
43
- response: captchaResponse
44
- })
45
- }
46
- );
46
+ const response = await betterFetch(siteVerifyURL, {
47
+ method: "POST",
48
+ headers: { "Content-Type": "application/json" },
49
+ body: JSON.stringify({
50
+ secret: secretKey,
51
+ response: captchaResponse,
52
+ ...remoteIP && { remoteip: remoteIP }
53
+ })
54
+ });
47
55
  if (!response.data || response.error) {
48
- return middlewareResponse({
49
- message: CAPTCHA_ERROR_CODES.SERVICE_UNAVAILABLE,
50
- status: 503
51
- });
56
+ throw new Error(INTERNAL_ERROR_CODES.SERVICE_UNAVAILABLE);
52
57
  }
53
58
  if (!response.data.success) {
54
59
  return middlewareResponse({
55
- message: CAPTCHA_ERROR_CODES.VERIFICATION_FAILED,
60
+ message: EXTERNAL_ERROR_CODES.VERIFICATION_FAILED,
56
61
  status: 403
57
62
  });
58
63
  }
59
64
  return void 0;
60
65
  };
61
66
 
62
- const googleReCAPTCHA = async ({
67
+ const encodeToURLParams = (obj) => {
68
+ if (typeof obj !== "object" || obj === null || Array.isArray(obj)) {
69
+ throw new Error("Input must be a non-null object.");
70
+ }
71
+ const params = new URLSearchParams();
72
+ for (const [key, value] of Object.entries(obj)) {
73
+ if (value !== void 0 && value !== null) {
74
+ params.append(key, String(value));
75
+ }
76
+ }
77
+ return params.toString();
78
+ };
79
+
80
+ const isV3 = (response) => {
81
+ return "score" in response && typeof response.score === "number";
82
+ };
83
+ const googleRecaptcha = async ({
63
84
  siteVerifyURL,
64
85
  captchaResponse,
65
- secretKey
86
+ secretKey,
87
+ minScore = 0.5,
88
+ remoteIP
66
89
  }) => {
67
90
  const response = await betterFetch(
68
91
  siteVerifyURL,
69
92
  {
70
93
  method: "POST",
71
- headers: { "Content-Type": "application/json" },
72
- body: JSON.stringify({
94
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
95
+ body: encodeToURLParams({
73
96
  secret: secretKey,
74
- response: captchaResponse
97
+ response: captchaResponse,
98
+ ...remoteIP && { remoteip: remoteIP }
75
99
  })
76
100
  }
77
101
  );
78
102
  if (!response.data || response.error) {
103
+ throw new Error(INTERNAL_ERROR_CODES.SERVICE_UNAVAILABLE);
104
+ }
105
+ if (!response.data.success || isV3(response.data) && response.data.score < minScore) {
79
106
  return middlewareResponse({
80
- message: CAPTCHA_ERROR_CODES.SERVICE_UNAVAILABLE,
81
- status: 503
107
+ message: EXTERNAL_ERROR_CODES.VERIFICATION_FAILED,
108
+ status: 403
82
109
  });
83
110
  }
111
+ return void 0;
112
+ };
113
+
114
+ const hCaptcha = async ({
115
+ siteVerifyURL,
116
+ captchaResponse,
117
+ secretKey,
118
+ siteKey,
119
+ remoteIP
120
+ }) => {
121
+ const response = await betterFetch(siteVerifyURL, {
122
+ method: "POST",
123
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
124
+ body: encodeToURLParams({
125
+ secret: secretKey,
126
+ response: captchaResponse,
127
+ ...siteKey && { sitekey: siteKey },
128
+ ...remoteIP && { remoteip: remoteIP }
129
+ })
130
+ });
131
+ if (!response.data || response.error) {
132
+ throw new Error(INTERNAL_ERROR_CODES.SERVICE_UNAVAILABLE);
133
+ }
84
134
  if (!response.data.success) {
85
135
  return middlewareResponse({
86
- message: CAPTCHA_ERROR_CODES.VERIFICATION_FAILED,
136
+ message: EXTERNAL_ERROR_CODES.VERIFICATION_FAILED,
87
137
  status: 403
88
138
  });
89
139
  }
@@ -92,37 +142,52 @@ const googleReCAPTCHA = async ({
92
142
 
93
143
  const captcha = (options) => ({
94
144
  id: "captcha",
95
- onRequest: async (request) => {
145
+ onRequest: async (request, ctx) => {
96
146
  try {
97
- if (request.method !== "POST") return void 0;
98
147
  const endpoints = options.endpoints?.length ? options.endpoints : defaultEndpoints;
99
148
  if (!endpoints.some((endpoint) => request.url.includes(endpoint)))
100
- return;
149
+ return void 0;
150
+ if (!options.secretKey) {
151
+ throw new Error(INTERNAL_ERROR_CODES.MISSING_SECRET_KEY);
152
+ }
101
153
  const captchaResponse = request.headers.get("x-captcha-response");
154
+ const remoteUserIP = request.headers.get("x-captcha-user-remote-ip") ?? void 0;
102
155
  if (!captchaResponse) {
103
156
  return middlewareResponse({
104
- message: CAPTCHA_ERROR_CODES.MISSING_RESPONSE,
157
+ message: EXTERNAL_ERROR_CODES.MISSING_RESPONSE,
105
158
  status: 400
106
159
  });
107
160
  }
108
161
  const siteVerifyURL = options.siteVerifyURLOverride || siteVerifyMap[options.provider];
162
+ const handlerParams = {
163
+ siteVerifyURL,
164
+ captchaResponse,
165
+ secretKey: options.secretKey,
166
+ remoteIP: remoteUserIP
167
+ };
109
168
  if (options.provider === Providers.CLOUDFLARE_TURNSTILE) {
110
- return await cloudflareTurnstile({
111
- secretKey: options.secretKey,
112
- captchaResponse,
113
- siteVerifyURL
114
- });
169
+ return await cloudflareTurnstile(handlerParams);
115
170
  }
116
171
  if (options.provider === Providers.GOOGLE_RECAPTCHA) {
117
- return await googleReCAPTCHA({
118
- secretKey: options.secretKey,
119
- captchaResponse,
120
- siteVerifyURL
172
+ return await googleRecaptcha({
173
+ ...handlerParams,
174
+ minScore: options.minScore
175
+ });
176
+ }
177
+ if (options.provider === Providers.HCAPTCHA) {
178
+ return await hCaptcha({
179
+ ...handlerParams,
180
+ siteKey: options.siteKey
121
181
  });
122
182
  }
123
183
  } catch (_error) {
184
+ const errorMessage = _error instanceof Error ? _error.message : void 0;
185
+ ctx.logger.error(errorMessage ?? "Unknown error", {
186
+ endpoint: request.url,
187
+ message: _error
188
+ });
124
189
  return middlewareResponse({
125
- message: CAPTCHA_ERROR_CODES.UNKNOWN_ERROR,
190
+ message: EXTERNAL_ERROR_CODES.UNKNOWN_ERROR,
126
191
  status: 500
127
192
  });
128
193
  }
@@ -2,11 +2,11 @@
2
2
 
3
3
  const zod = require('zod');
4
4
  require('better-call');
5
- const refreshToken = require('../../shared/better-auth.BDYXUcLv.cjs');
5
+ const refreshToken = require('../../shared/better-auth.Dg0siV5C.cjs');
6
6
  require('../../shared/better-auth.DiSjtgs9.cjs');
7
7
  require('@better-auth/utils/base64');
8
8
  require('@better-auth/utils/hmac');
9
- require('../../shared/better-auth.C5H9XEzZ.cjs');
9
+ require('../../shared/better-auth.DcWKCjjf.cjs');
10
10
  require('../../shared/better-auth.GpOOav9x.cjs');
11
11
  require('defu');
12
12
  require('../../cookies/index.cjs');
@@ -42,9 +42,6 @@ const customSession = (fn, options) => {
42
42
  "/get-session",
43
43
  {
44
44
  method: "GET",
45
- metadata: {
46
- CUSTOM_SESSION: true
47
- },
48
45
  query: zod.z.optional(
49
46
  zod.z.object({
50
47
  /**
@@ -59,6 +56,28 @@ const customSession = (fn, options) => {
59
56
  }).optional()
60
57
  })
61
58
  ),
59
+ metadata: {
60
+ CUSTOM_SESSION: true,
61
+ openapi: {
62
+ description: "Get custom session data",
63
+ responses: {
64
+ "200": {
65
+ description: "Success",
66
+ content: {
67
+ "application/json": {
68
+ schema: {
69
+ type: "array",
70
+ nullable: true,
71
+ items: {
72
+ $ref: "#/components/schemas/Session"
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ },
62
81
  requireHeaders: true
63
82
  },
64
83
  async (ctx) => {