@gatwech/auth 1.0.0-beta.18

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 (422) hide show
  1. package/README.md +31 -0
  2. package/dist/access-BO2g7QVe.mjs +45 -0
  3. package/dist/access-C6O_osEz.mjs +79 -0
  4. package/dist/access-DT1f6l5k.mjs +51 -0
  5. package/dist/adapter-factory-BZ2Qiqpn.mjs +640 -0
  6. package/dist/adapters/drizzle-adapter/index.d.mts +47 -0
  7. package/dist/adapters/drizzle-adapter/index.mjs +208 -0
  8. package/dist/adapters/index.d.mts +132 -0
  9. package/dist/adapters/index.mjs +18 -0
  10. package/dist/adapters/kysely-adapter/index.d.mts +47 -0
  11. package/dist/adapters/kysely-adapter/index.mjs +11 -0
  12. package/dist/adapters/memory-adapter/index.d.mts +14 -0
  13. package/dist/adapters/memory-adapter/index.mjs +154 -0
  14. package/dist/adapters/mongodb-adapter/index.d.mts +35 -0
  15. package/dist/adapters/mongodb-adapter/index.mjs +315 -0
  16. package/dist/adapters/prisma-adapter/index.d.mts +34 -0
  17. package/dist/adapters/prisma-adapter/index.mjs +159 -0
  18. package/dist/adapters/test.d.mts +81 -0
  19. package/dist/adapters/test.mjs +793 -0
  20. package/dist/admin-Bcq53Nwj.mjs +743 -0
  21. package/dist/admin-DtfO1PLg.d.mts +1689 -0
  22. package/dist/anonymous-CRt1imBW.mjs +107 -0
  23. package/dist/api/index.d.mts +6 -0
  24. package/dist/api/index.mjs +17 -0
  25. package/dist/api-0pR_I-Nx.mjs +3139 -0
  26. package/dist/auth-CBUoBX6o.mjs +233 -0
  27. package/dist/bearer-Djf_awfo.mjs +63 -0
  28. package/dist/bun-sqlite-dialect-CeNvMaZz.mjs +155 -0
  29. package/dist/captcha-BqaMxlKC.mjs +178 -0
  30. package/dist/chunk-BK_LfMhE.mjs +40 -0
  31. package/dist/client/index.d.mts +186 -0
  32. package/dist/client/index.mjs +7 -0
  33. package/dist/client/plugins/index.d.mts +949 -0
  34. package/dist/client/plugins/index.mjs +539 -0
  35. package/dist/client/react/index.d.mts +179 -0
  36. package/dist/client/react/index.mjs +69 -0
  37. package/dist/client-BOX93C3d.d.mts +1250 -0
  38. package/dist/client-CNY0tn9g.d.mts +628 -0
  39. package/dist/client-CygJhqeB.mjs +29 -0
  40. package/dist/client-WiN43tAS.mjs +17 -0
  41. package/dist/client-aExCkfwm.mjs +30 -0
  42. package/dist/cookies/index.d.mts +7 -0
  43. package/dist/cookies/index.mjs +7 -0
  44. package/dist/cookies-cJObLwn1.mjs +597 -0
  45. package/dist/crypto/index.d.mts +44 -0
  46. package/dist/crypto/index.mjs +4 -0
  47. package/dist/crypto-Bb42eMrH.mjs +70 -0
  48. package/dist/custom-session-L3t7ecsd.mjs +67 -0
  49. package/dist/date-Cx2yCiC4.mjs +115 -0
  50. package/dist/db/index.d.mts +7 -0
  51. package/dist/db/index.mjs +15 -0
  52. package/dist/db-BrstmDhc.mjs +1124 -0
  53. package/dist/device-authorization-V4s3h4Mj.mjs +557 -0
  54. package/dist/dialect-CeddeGHf.mjs +72 -0
  55. package/dist/email-otp-BtDHSw14.mjs +592 -0
  56. package/dist/esm-C-QicDNz.mjs +4090 -0
  57. package/dist/generic-oauth-CL5X27ZI.mjs +445 -0
  58. package/dist/get-request-ip-DSjrEpGo.mjs +27 -0
  59. package/dist/get-tables-BQP7YW9c.mjs +249 -0
  60. package/dist/has-permission-BpAr7uCn.mjs +14 -0
  61. package/dist/haveibeenpwned-cMpJvmzI.mjs +43 -0
  62. package/dist/helper-tmxW3BHj.d.mts +21 -0
  63. package/dist/index-34ONrP8l.d.mts +503 -0
  64. package/dist/index-65G5U5DB-DSdjzreF.d.mts +2543 -0
  65. package/dist/index-B-XKqFvY.d.mts +30 -0
  66. package/dist/index-B3n8e37d.d.mts +165 -0
  67. package/dist/index-BBm8nQ9Q.d.mts +42 -0
  68. package/dist/index-BHoQlf7a.d.mts +7699 -0
  69. package/dist/index-BYMI9r_d.d.mts +257 -0
  70. package/dist/index-BqhKCbPH.d.mts +36 -0
  71. package/dist/index-Buhn3hkR.d.mts +433 -0
  72. package/dist/index-C-u1h_WX.d.mts +174 -0
  73. package/dist/index-C7fQuk-V.d.mts +41 -0
  74. package/dist/index-CM-CFWwr.d.mts +1919 -0
  75. package/dist/index-CuFzhoS6.d.mts +359 -0
  76. package/dist/index-Cxi7TbLE.d.mts +11347 -0
  77. package/dist/index-DB7t8whN.d.mts +1 -0
  78. package/dist/index-DKNNV1kb.d.mts +626 -0
  79. package/dist/index-DR0xXno9.d.mts +113 -0
  80. package/dist/index-D_k662QG.d.mts +833 -0
  81. package/dist/index-DaBcikv9.d.mts +118 -0
  82. package/dist/index-DlaMq1nb.d.mts +955 -0
  83. package/dist/index-DoXZYQpq.d.mts +290 -0
  84. package/dist/index-G6V0Z_Mn.d.mts +125 -0
  85. package/dist/index-z0KSvE5i.d.mts +246 -0
  86. package/dist/index-zjjNBRY2.d.mts +95 -0
  87. package/dist/index.d.mts +12 -0
  88. package/dist/index.mjs +33 -0
  89. package/dist/integrations/next-js.d.mts +21 -0
  90. package/dist/integrations/next-js.mjs +62 -0
  91. package/dist/integrations/node.d.mts +15 -0
  92. package/dist/integrations/node.mjs +15 -0
  93. package/dist/integrations/react-start.d.mts +15 -0
  94. package/dist/integrations/react-start.mjs +46 -0
  95. package/dist/json-D0TBLy4q.mjs +24 -0
  96. package/dist/jwt-CmxZAGe2.mjs +94 -0
  97. package/dist/jwt-lHV4QHpD.mjs +387 -0
  98. package/dist/kysely-adapter-DpzYO8Yf.mjs +181 -0
  99. package/dist/magic-link-Bk-ueorR.mjs +176 -0
  100. package/dist/misc-beA1w3XV.mjs +7 -0
  101. package/dist/multi-session-DRrLKrg9.mjs +144 -0
  102. package/dist/node-sqlite-dialect-BcKxBQnm.mjs +155 -0
  103. package/dist/oauth-proxy-D1sWh9B_.mjs +133 -0
  104. package/dist/oauth2/index.d.mts +60 -0
  105. package/dist/oauth2/index.mjs +19 -0
  106. package/dist/one-tap-DMswkTEc.mjs +113 -0
  107. package/dist/organization-BArHO_5v.mjs +3857 -0
  108. package/dist/parser-DcrIEuXE.mjs +73 -0
  109. package/dist/passkey-CcD4CnhM.mjs +558 -0
  110. package/dist/password-sVC4nePO.mjs +25 -0
  111. package/dist/permission-DLYUF3cW.mjs +15 -0
  112. package/dist/phone-number-rHDIlh-2.mjs +485 -0
  113. package/dist/plugin-helper-4L-lzsjZ.mjs +16 -0
  114. package/dist/plugins/access/index.d.mts +3 -0
  115. package/dist/plugins/access/index.mjs +3 -0
  116. package/dist/plugins/admin/access/index.d.mts +116 -0
  117. package/dist/plugins/admin/access/index.mjs +4 -0
  118. package/dist/plugins/admin/index.d.mts +9 -0
  119. package/dist/plugins/admin/index.mjs +22 -0
  120. package/dist/plugins/anonymous/index.d.mts +7 -0
  121. package/dist/plugins/anonymous/index.mjs +18 -0
  122. package/dist/plugins/bearer/index.d.mts +2 -0
  123. package/dist/plugins/bearer/index.mjs +8 -0
  124. package/dist/plugins/captcha/index.d.mts +2 -0
  125. package/dist/plugins/captcha/index.mjs +4 -0
  126. package/dist/plugins/custom-session/index.d.mts +7 -0
  127. package/dist/plugins/custom-session/index.mjs +19 -0
  128. package/dist/plugins/device-authorization/index.d.mts +4 -0
  129. package/dist/plugins/device-authorization/index.mjs +18 -0
  130. package/dist/plugins/email-otp/index.d.mts +3 -0
  131. package/dist/plugins/email-otp/index.mjs +19 -0
  132. package/dist/plugins/generic-oauth/index.d.mts +7 -0
  133. package/dist/plugins/generic-oauth/index.mjs +18 -0
  134. package/dist/plugins/haveibeenpwned/index.d.mts +2 -0
  135. package/dist/plugins/haveibeenpwned/index.mjs +18 -0
  136. package/dist/plugins/index.d.mts +139 -0
  137. package/dist/plugins/index.mjs +47 -0
  138. package/dist/plugins/jwt/index.d.mts +7 -0
  139. package/dist/plugins/jwt/index.mjs +18 -0
  140. package/dist/plugins/magic-link/index.d.mts +2 -0
  141. package/dist/plugins/magic-link/index.mjs +18 -0
  142. package/dist/plugins/multi-session/index.d.mts +3 -0
  143. package/dist/plugins/multi-session/index.mjs +18 -0
  144. package/dist/plugins/oauth-proxy/index.d.mts +2 -0
  145. package/dist/plugins/oauth-proxy/index.mjs +18 -0
  146. package/dist/plugins/one-tap/index.d.mts +2 -0
  147. package/dist/plugins/one-tap/index.mjs +18 -0
  148. package/dist/plugins/one-time-token/index.d.mts +7 -0
  149. package/dist/plugins/one-time-token/index.mjs +47 -0
  150. package/dist/plugins/organization/access/index.d.mts +4 -0
  151. package/dist/plugins/organization/access/index.mjs +4 -0
  152. package/dist/plugins/organization/index.d.mts +9 -0
  153. package/dist/plugins/organization/index.mjs +22 -0
  154. package/dist/plugins/passkey/index.d.mts +7 -0
  155. package/dist/plugins/passkey/index.mjs +18 -0
  156. package/dist/plugins/phone-number/index.d.mts +7 -0
  157. package/dist/plugins/phone-number/index.mjs +18 -0
  158. package/dist/plugins/two-factor/index.d.mts +7 -0
  159. package/dist/plugins/two-factor/index.mjs +20 -0
  160. package/dist/plugins/username/index.d.mts +4 -0
  161. package/dist/plugins/username/index.mjs +18 -0
  162. package/dist/plugins-3jfNste3.mjs +1544 -0
  163. package/dist/plugins-hFZT3hmK.d.mts +14 -0
  164. package/dist/promise-8rrEHRXd.mjs +23154 -0
  165. package/dist/proxy-CL9PZXJA.mjs +441 -0
  166. package/dist/session-Dgp133Yt.mjs +413 -0
  167. package/dist/social-providers/index.d.mts +1 -0
  168. package/dist/social-providers/index.mjs +3 -0
  169. package/dist/src/adapters/adapter-factory/index.d.ts +10 -0
  170. package/dist/src/adapters/adapter-factory/types.d.ts +124 -0
  171. package/dist/src/adapters/create-test-suite.d.ts +97 -0
  172. package/dist/src/adapters/drizzle-adapter/drizzle-adapter.d.ts +43 -0
  173. package/dist/src/adapters/drizzle-adapter/index.d.ts +1 -0
  174. package/dist/src/adapters/drizzle-adapter/test/generate-schema.d.ts +12 -0
  175. package/dist/src/adapters/index.d.ts +21 -0
  176. package/dist/src/adapters/kysely-adapter/bun-sqlite-dialect.d.ts +58 -0
  177. package/dist/src/adapters/kysely-adapter/dialect.d.ts +13 -0
  178. package/dist/src/adapters/kysely-adapter/index.d.ts +3 -0
  179. package/dist/src/adapters/kysely-adapter/kysely-adapter.d.ts +32 -0
  180. package/dist/src/adapters/kysely-adapter/node-sqlite-dialect.d.ts +58 -0
  181. package/dist/src/adapters/kysely-adapter/types.d.ts +1 -0
  182. package/dist/src/adapters/memory-adapter/index.d.ts +1 -0
  183. package/dist/src/adapters/memory-adapter/memory-adapter.d.ts +9 -0
  184. package/dist/src/adapters/mongodb-adapter/index.d.ts +1 -0
  185. package/dist/src/adapters/mongodb-adapter/mongodb-adapter.d.ts +31 -0
  186. package/dist/src/adapters/prisma-adapter/index.d.ts +1 -0
  187. package/dist/src/adapters/prisma-adapter/prisma-adapter.d.ts +32 -0
  188. package/dist/src/adapters/prisma-adapter/test/auth.d.ts +3 -0
  189. package/dist/src/adapters/prisma-adapter/test/generate-auth-config.d.ts +2 -0
  190. package/dist/src/adapters/prisma-adapter/test/generate-prisma-schema.d.ts +3 -0
  191. package/dist/src/adapters/prisma-adapter/test/get-prisma-client.d.ts +7 -0
  192. package/dist/src/adapters/prisma-adapter/test/push-prisma-schema.d.ts +1 -0
  193. package/dist/src/adapters/test-adapter.d.ts +61 -0
  194. package/dist/src/adapters/test.d.ts +78 -0
  195. package/dist/src/adapters/tests/auth-flow.d.ts +22 -0
  196. package/dist/src/adapters/tests/index.d.ts +5 -0
  197. package/dist/src/adapters/tests/normal.d.ts +87 -0
  198. package/dist/src/adapters/tests/number-id.d.ts +17 -0
  199. package/dist/src/adapters/tests/performance.d.ts +24 -0
  200. package/dist/src/adapters/tests/transactions.d.ts +20 -0
  201. package/dist/src/adapters/utils.d.ts +3 -0
  202. package/dist/src/api/index.d.ts +7150 -0
  203. package/dist/src/api/middlewares/index.d.ts +2 -0
  204. package/dist/src/api/middlewares/oauth.d.ts +15 -0
  205. package/dist/src/api/middlewares/origin-check.d.ts +8 -0
  206. package/dist/src/api/rate-limiter/index.d.ts +13 -0
  207. package/dist/src/api/routes/account.d.ts +623 -0
  208. package/dist/src/api/routes/callback.d.ts +68 -0
  209. package/dist/src/api/routes/email-verification.d.ts +266 -0
  210. package/dist/src/api/routes/error.d.ts +51 -0
  211. package/dist/src/api/routes/index.d.ts +11 -0
  212. package/dist/src/api/routes/ok.d.ts +61 -0
  213. package/dist/src/api/routes/reset-password.d.ts +203 -0
  214. package/dist/src/api/routes/session.d.ts +586 -0
  215. package/dist/src/api/routes/sign-in.d.ts +298 -0
  216. package/dist/src/api/routes/sign-out.d.ts +59 -0
  217. package/dist/src/api/routes/sign-up.d.ts +625 -0
  218. package/dist/src/api/routes/update-user.d.ts +862 -0
  219. package/dist/src/api/to-auth-endpoints.d.ts +3 -0
  220. package/dist/src/auth.d.ts +25 -0
  221. package/dist/src/client/broadcast-channel.d.ts +12 -0
  222. package/dist/src/client/config.d.ts +85 -0
  223. package/dist/src/client/fetch-plugins.d.ts +14 -0
  224. package/dist/src/client/index.d.ts +15 -0
  225. package/dist/src/client/parser.d.ts +12 -0
  226. package/dist/src/client/path-to-object.d.ts +63 -0
  227. package/dist/src/client/plugins/index.d.ts +21 -0
  228. package/dist/src/client/plugins/infer-plugin.d.ts +11 -0
  229. package/dist/src/client/proxy.d.ts +8 -0
  230. package/dist/src/client/query.d.ts +16 -0
  231. package/dist/src/client/react/index.d.ts +130 -0
  232. package/dist/src/client/react/react-store.d.ts +43 -0
  233. package/dist/src/client/session-atom.d.ts +18 -0
  234. package/dist/src/client/session-refresh.d.ts +17 -0
  235. package/dist/src/client/test-plugin.d.ts +147 -0
  236. package/dist/src/client/types.d.ts +49 -0
  237. package/dist/src/client/vanilla.d.ts +124 -0
  238. package/dist/src/cookies/check-cookies.d.ts +4 -0
  239. package/dist/src/cookies/cookie-utils.d.ts +16 -0
  240. package/dist/src/cookies/index.d.ts +56 -0
  241. package/dist/src/cookies/session-store.d.ts +43 -0
  242. package/dist/src/crypto/buffer.d.ts +4 -0
  243. package/dist/src/crypto/index.d.ts +14 -0
  244. package/dist/src/crypto/jwt.d.ts +4 -0
  245. package/dist/src/crypto/password.d.ts +5 -0
  246. package/dist/src/crypto/random.d.ts +1 -0
  247. package/dist/src/db/field.d.ts +97 -0
  248. package/dist/src/db/get-migration.d.ts +18 -0
  249. package/dist/src/db/get-schema.d.ts +6 -0
  250. package/dist/src/db/get-tables.d.ts +3 -0
  251. package/dist/src/db/index.d.ts +10 -0
  252. package/dist/src/db/internal-adapter.d.ts +9 -0
  253. package/dist/src/db/schema.d.ts +76 -0
  254. package/dist/src/db/to-zod.d.ts +31 -0
  255. package/dist/src/db/utils.d.ts +6 -0
  256. package/dist/src/db/with-hooks.d.ts +27 -0
  257. package/dist/src/index.d.ts +14 -0
  258. package/dist/src/init.d.ts +2 -0
  259. package/dist/src/integrations/next-js.d.ts +15 -0
  260. package/dist/src/integrations/node.d.ts +6 -0
  261. package/dist/src/integrations/react-start.d.ts +9 -0
  262. package/dist/src/oauth2/index.d.ts +4 -0
  263. package/dist/src/oauth2/link-account.d.ts +41 -0
  264. package/dist/src/oauth2/state.d.ts +21 -0
  265. package/dist/src/oauth2/utils.d.ts +3 -0
  266. package/dist/src/plugins/access/access.d.ts +25 -0
  267. package/dist/src/plugins/access/index.d.ts +2 -0
  268. package/dist/src/plugins/access/types.d.ts +14 -0
  269. package/dist/src/plugins/additional-fields/client.d.ts +91 -0
  270. package/dist/src/plugins/admin/access/index.d.ts +1 -0
  271. package/dist/src/plugins/admin/access/statement.d.ts +110 -0
  272. package/dist/src/plugins/admin/admin.d.ts +1570 -0
  273. package/dist/src/plugins/admin/client.d.ts +62 -0
  274. package/dist/src/plugins/admin/error-codes.d.ts +21 -0
  275. package/dist/src/plugins/admin/has-permission.d.ts +21 -0
  276. package/dist/src/plugins/admin/index.d.ts +2 -0
  277. package/dist/src/plugins/admin/schema.d.ts +36 -0
  278. package/dist/src/plugins/admin/types.d.ts +77 -0
  279. package/dist/src/plugins/anonymous/client.d.ts +8 -0
  280. package/dist/src/plugins/anonymous/index.d.ts +159 -0
  281. package/dist/src/plugins/api-key/client.d.ts +11 -0
  282. package/dist/src/plugins/api-key/index.d.ts +1431 -0
  283. package/dist/src/plugins/api-key/rate-limit.d.ts +20 -0
  284. package/dist/src/plugins/api-key/routes/create-api-key.d.ts +244 -0
  285. package/dist/src/plugins/api-key/routes/delete-all-expired-api-keys.d.ts +45 -0
  286. package/dist/src/plugins/api-key/routes/delete-api-key.d.ts +112 -0
  287. package/dist/src/plugins/api-key/routes/get-api-key.d.ts +234 -0
  288. package/dist/src/plugins/api-key/routes/index.d.ts +1136 -0
  289. package/dist/src/plugins/api-key/routes/list-api-keys.d.ts +231 -0
  290. package/dist/src/plugins/api-key/routes/update-api-key.d.ts +235 -0
  291. package/dist/src/plugins/api-key/routes/verify-api-key.d.ts +80 -0
  292. package/dist/src/plugins/api-key/schema.d.ts +188 -0
  293. package/dist/src/plugins/api-key/types.d.ts +285 -0
  294. package/dist/src/plugins/bearer/index.d.ts +31 -0
  295. package/dist/src/plugins/captcha/constants.d.ts +9 -0
  296. package/dist/src/plugins/captcha/error-codes.d.ts +9 -0
  297. package/dist/src/plugins/captcha/index.d.ts +7 -0
  298. package/dist/src/plugins/captcha/types.d.ts +23 -0
  299. package/dist/src/plugins/captcha/utils.d.ts +1 -0
  300. package/dist/src/plugins/captcha/verify-handlers/captchafox.d.ts +11 -0
  301. package/dist/src/plugins/captcha/verify-handlers/cloudflare-turnstile.d.ts +10 -0
  302. package/dist/src/plugins/captcha/verify-handlers/google-recaptcha.d.ts +11 -0
  303. package/dist/src/plugins/captcha/verify-handlers/h-captcha.d.ts +11 -0
  304. package/dist/src/plugins/captcha/verify-handlers/index.d.ts +4 -0
  305. package/dist/src/plugins/custom-session/client.d.ts +12 -0
  306. package/dist/src/plugins/custom-session/index.d.ts +89 -0
  307. package/dist/src/plugins/device-authorization/client.d.ts +12 -0
  308. package/dist/src/plugins/device-authorization/index.d.ts +568 -0
  309. package/dist/src/plugins/device-authorization/schema.d.ts +56 -0
  310. package/dist/src/plugins/email-otp/client.d.ts +9 -0
  311. package/dist/src/plugins/email-otp/index.d.ts +826 -0
  312. package/dist/src/plugins/email-otp/utils.d.ts +2 -0
  313. package/dist/src/plugins/generic-oauth/client.d.ts +5 -0
  314. package/dist/src/plugins/generic-oauth/index.d.ts +428 -0
  315. package/dist/src/plugins/haveibeenpwned/index.d.ts +25 -0
  316. package/dist/src/plugins/index.d.ts +28 -0
  317. package/dist/src/plugins/jwt/adapter.d.ts +8 -0
  318. package/dist/src/plugins/jwt/client.d.ts +5 -0
  319. package/dist/src/plugins/jwt/index.d.ts +276 -0
  320. package/dist/src/plugins/jwt/schema.d.ts +18 -0
  321. package/dist/src/plugins/jwt/sign.d.ts +8 -0
  322. package/dist/src/plugins/jwt/types.d.ts +175 -0
  323. package/dist/src/plugins/jwt/utils.d.ts +46 -0
  324. package/dist/src/plugins/last-login-method/client.d.ts +34 -0
  325. package/dist/src/plugins/last-login-method/index.d.ts +103 -0
  326. package/dist/src/plugins/magic-link/client.d.ts +5 -0
  327. package/dist/src/plugins/magic-link/index.d.ts +253 -0
  328. package/dist/src/plugins/magic-link/utils.d.ts +1 -0
  329. package/dist/src/plugins/multi-session/client.d.ts +9 -0
  330. package/dist/src/plugins/multi-session/index.d.ts +284 -0
  331. package/dist/src/plugins/oauth-proxy/index.d.ts +119 -0
  332. package/dist/src/plugins/one-tap/client.d.ts +81 -0
  333. package/dist/src/plugins/one-tap/index.d.ts +114 -0
  334. package/dist/src/plugins/one-time-token/client.d.ts +5 -0
  335. package/dist/src/plugins/one-time-token/index.d.ts +170 -0
  336. package/dist/src/plugins/one-time-token/utils.d.ts +1 -0
  337. package/dist/src/plugins/organization/access/index.d.ts +1 -0
  338. package/dist/src/plugins/organization/access/statement.d.ts +241 -0
  339. package/dist/src/plugins/organization/adapter.d.ts +685 -0
  340. package/dist/src/plugins/organization/call.d.ts +55 -0
  341. package/dist/src/plugins/organization/client.d.ts +344 -0
  342. package/dist/src/plugins/organization/error-codes.d.ts +58 -0
  343. package/dist/src/plugins/organization/has-permission.d.ts +13 -0
  344. package/dist/src/plugins/organization/index.d.ts +4 -0
  345. package/dist/src/plugins/organization/organization.d.ts +412 -0
  346. package/dist/src/plugins/organization/permission.d.ts +27 -0
  347. package/dist/src/plugins/organization/routes/crud-access-control.d.ts +701 -0
  348. package/dist/src/plugins/organization/routes/crud-invites.d.ts +1522 -0
  349. package/dist/src/plugins/organization/routes/crud-members.d.ts +1220 -0
  350. package/dist/src/plugins/organization/routes/crud-org.d.ts +1399 -0
  351. package/dist/src/plugins/organization/routes/crud-team.d.ts +1323 -0
  352. package/dist/src/plugins/organization/schema.d.ts +366 -0
  353. package/dist/src/plugins/organization/types.d.ts +737 -0
  354. package/dist/src/plugins/passkey/client.d.ts +190 -0
  355. package/dist/src/plugins/passkey/error-codes.d.ts +9 -0
  356. package/dist/src/plugins/passkey/index.d.ts +838 -0
  357. package/dist/src/plugins/passkey/schema.d.ts +50 -0
  358. package/dist/src/plugins/passkey/types.d.ts +69 -0
  359. package/dist/src/plugins/passkey/utils.d.ts +2 -0
  360. package/dist/src/plugins/phone-number/client.d.ts +9 -0
  361. package/dist/src/plugins/phone-number/index.d.ts +622 -0
  362. package/dist/src/plugins/phone-number/phone-number-error.d.ts +10 -0
  363. package/dist/src/plugins/two-factor/backup-codes/index.d.ts +387 -0
  364. package/dist/src/plugins/two-factor/client.d.ts +28 -0
  365. package/dist/src/plugins/two-factor/constant.d.ts +2 -0
  366. package/dist/src/plugins/two-factor/error-code.d.ts +11 -0
  367. package/dist/src/plugins/two-factor/index.d.ts +1014 -0
  368. package/dist/src/plugins/two-factor/otp/index.d.ts +282 -0
  369. package/dist/src/plugins/two-factor/schema.d.ts +35 -0
  370. package/dist/src/plugins/two-factor/totp/index.d.ts +298 -0
  371. package/dist/src/plugins/two-factor/types.d.ts +50 -0
  372. package/dist/src/plugins/two-factor/utils.d.ts +1 -0
  373. package/dist/src/plugins/two-factor/verify-two-factor.d.ts +59 -0
  374. package/dist/src/plugins/username/client.d.ts +5 -0
  375. package/dist/src/plugins/username/error-codes.d.ts +10 -0
  376. package/dist/src/plugins/username/index.d.ts +313 -0
  377. package/dist/src/plugins/username/schema.d.ts +27 -0
  378. package/dist/src/social-providers/index.d.ts +1 -0
  379. package/dist/src/test-utils/headers.d.ts +5 -0
  380. package/dist/src/test-utils/index.d.ts +2 -0
  381. package/dist/src/test-utils/test-instance.d.ts +17849 -0
  382. package/dist/src/types/adapter.d.ts +21 -0
  383. package/dist/src/types/api.d.ts +29 -0
  384. package/dist/src/types/helper.d.ts +32 -0
  385. package/dist/src/types/index.d.ts +7 -0
  386. package/dist/src/types/models.d.ts +13 -0
  387. package/dist/src/types/plugins.d.ts +14 -0
  388. package/dist/src/utils/await-object.d.ts +3 -0
  389. package/dist/src/utils/boolean.d.ts +1 -0
  390. package/dist/src/utils/clone.d.ts +1 -0
  391. package/dist/src/utils/constants.d.ts +1 -0
  392. package/dist/src/utils/date.d.ts +1 -0
  393. package/dist/src/utils/ensure-utc.d.ts +1 -0
  394. package/dist/src/utils/get-request-ip.d.ts +2 -0
  395. package/dist/src/utils/hashing.d.ts +6 -0
  396. package/dist/src/utils/hide-metadata.d.ts +3 -0
  397. package/dist/src/utils/id.d.ts +1 -0
  398. package/dist/src/utils/import-util.d.ts +1 -0
  399. package/dist/src/utils/index.d.ts +5 -0
  400. package/dist/src/utils/is-atom.d.ts +2 -0
  401. package/dist/src/utils/is-promise.d.ts +1 -0
  402. package/dist/src/utils/json.d.ts +1 -0
  403. package/dist/src/utils/merger.d.ts +1 -0
  404. package/dist/src/utils/middleware-response.d.ts +8 -0
  405. package/dist/src/utils/misc.d.ts +1 -0
  406. package/dist/src/utils/password.d.ts +6 -0
  407. package/dist/src/utils/plugin-helper.d.ts +5 -0
  408. package/dist/src/utils/shim.d.ts +3 -0
  409. package/dist/src/utils/time.d.ts +4 -0
  410. package/dist/src/utils/url.d.ts +4 -0
  411. package/dist/src/utils/wildcard.d.ts +45 -0
  412. package/dist/test-utils/index.d.mts +17870 -0
  413. package/dist/test-utils/index.mjs +272 -0
  414. package/dist/two-factor-ClUXxom2.mjs +914 -0
  415. package/dist/types/index.d.mts +6 -0
  416. package/dist/types/index.mjs +3 -0
  417. package/dist/types-B1OL7hyf.d.mts +4 -0
  418. package/dist/types-Bjn15Uy6.mjs +1 -0
  419. package/dist/url-VB2gAbTI.mjs +59 -0
  420. package/dist/username-DiGklOGl.mjs +278 -0
  421. package/dist/utils-SOMB4Px5.mjs +132 -0
  422. package/package.json +447 -0
@@ -0,0 +1,3857 @@
1
+ import { t as generateId } from "./utils-SOMB4Px5.mjs";
2
+ import { t as APIError$1 } from "./api-0pR_I-Nx.mjs";
3
+ import { c as setSessionCookie } from "./cookies-cJObLwn1.mjs";
4
+ import { t as getDate } from "./date-Cx2yCiC4.mjs";
5
+ import { i as toZodSchema } from "./db-BrstmDhc.mjs";
6
+ import { a as requestOnlySessionMiddleware, r as getSessionFromCtx, u as sessionMiddleware } from "./session-Dgp133Yt.mjs";
7
+ import { n as parser_default } from "./parser-DcrIEuXE.mjs";
8
+ import { r as defaultRoles } from "./access-C6O_osEz.mjs";
9
+ import { n as hasPermissionFn, t as cacheAllRoles } from "./permission-DLYUF3cW.mjs";
10
+ import { getCurrentAdapter } from "@gatwech/core/context";
11
+ import { BASE_ERROR_CODES, PayvoAuthError } from "@gatwech/core/error";
12
+ import { defineErrorCodes } from "@gatwech/core/utils";
13
+ import { APIError } from "better-call";
14
+ import { createAuthEndpoint, createAuthMiddleware } from "@gatwech/core/api";
15
+ import * as z$1 from "zod";
16
+ import { z } from "zod";
17
+
18
+ //#region src/utils/shim.ts
19
+ const shimContext = (originalObject, newContext) => {
20
+ const shimmedObj = {};
21
+ for (const [key, value] of Object.entries(originalObject)) {
22
+ shimmedObj[key] = (ctx) => {
23
+ return value({
24
+ ...ctx,
25
+ context: {
26
+ ...newContext,
27
+ ...ctx.context
28
+ }
29
+ });
30
+ };
31
+ shimmedObj[key].path = value.path;
32
+ shimmedObj[key].method = value.method;
33
+ shimmedObj[key].options = value.options;
34
+ shimmedObj[key].headers = value.headers;
35
+ }
36
+ return shimmedObj;
37
+ };
38
+
39
+ //#endregion
40
+ //#region src/plugins/organization/adapter.ts
41
+ const getOrgAdapter = (context, options) => {
42
+ const baseAdapter = context.adapter;
43
+ return {
44
+ findOrganizationBySlug: async (slug) => {
45
+ return await (await getCurrentAdapter(baseAdapter)).findOne({
46
+ model: "organization",
47
+ where: [{
48
+ field: "slug",
49
+ value: slug
50
+ }]
51
+ });
52
+ },
53
+ createOrganization: async (data) => {
54
+ const organization$1 = await (await getCurrentAdapter(baseAdapter)).create({
55
+ model: "organization",
56
+ data: {
57
+ ...data.organization,
58
+ metadata: data.organization.metadata ? JSON.stringify(data.organization.metadata) : void 0
59
+ },
60
+ forceAllowId: true
61
+ });
62
+ return {
63
+ ...organization$1,
64
+ metadata: organization$1.metadata && typeof organization$1.metadata === "string" ? JSON.parse(organization$1.metadata) : void 0
65
+ };
66
+ },
67
+ findMemberByEmail: async (data) => {
68
+ const adapter = await getCurrentAdapter(baseAdapter);
69
+ const user = await adapter.findOne({
70
+ model: "user",
71
+ where: [{
72
+ field: "email",
73
+ value: data.email.toLowerCase()
74
+ }]
75
+ });
76
+ if (!user) return null;
77
+ const member = await adapter.findOne({
78
+ model: "member",
79
+ where: [{
80
+ field: "organizationId",
81
+ value: data.organizationId
82
+ }, {
83
+ field: "userId",
84
+ value: user.id
85
+ }]
86
+ });
87
+ if (!member) return null;
88
+ return {
89
+ ...member,
90
+ user: {
91
+ id: user.id,
92
+ name: user.name,
93
+ email: user.email,
94
+ image: user.image
95
+ }
96
+ };
97
+ },
98
+ listMembers: async (data) => {
99
+ const adapter = await getCurrentAdapter(baseAdapter);
100
+ const members = await Promise.all([adapter.findMany({
101
+ model: "member",
102
+ where: [{
103
+ field: "organizationId",
104
+ value: data.organizationId
105
+ }, ...data.filter?.field ? [{
106
+ field: data.filter?.field,
107
+ value: data.filter?.value
108
+ }] : []],
109
+ limit: data.limit || options?.membershipLimit || 100,
110
+ offset: data.offset || 0,
111
+ sortBy: data.sortBy ? {
112
+ field: data.sortBy,
113
+ direction: data.sortOrder || "asc"
114
+ } : void 0
115
+ }), adapter.count({
116
+ model: "member",
117
+ where: [{
118
+ field: "organizationId",
119
+ value: data.organizationId
120
+ }, ...data.filter?.field ? [{
121
+ field: data.filter?.field,
122
+ value: data.filter?.value
123
+ }] : []]
124
+ })]);
125
+ const users = await adapter.findMany({
126
+ model: "user",
127
+ where: [{
128
+ field: "id",
129
+ value: members[0].map((member) => member.userId),
130
+ operator: "in"
131
+ }]
132
+ });
133
+ return {
134
+ members: members[0].map((member) => {
135
+ const user = users.find((user$1) => user$1.id === member.userId);
136
+ if (!user) throw new PayvoAuthError("Unexpected error: User not found for member");
137
+ return {
138
+ ...member,
139
+ user: {
140
+ id: user.id,
141
+ name: user.name,
142
+ email: user.email,
143
+ image: user.image
144
+ }
145
+ };
146
+ }),
147
+ total: members[1]
148
+ };
149
+ },
150
+ findMemberByOrgId: async (data) => {
151
+ const adapter = await getCurrentAdapter(baseAdapter);
152
+ const [member, user] = await Promise.all([await adapter.findOne({
153
+ model: "member",
154
+ where: [{
155
+ field: "userId",
156
+ value: data.userId
157
+ }, {
158
+ field: "organizationId",
159
+ value: data.organizationId
160
+ }]
161
+ }), await adapter.findOne({
162
+ model: "user",
163
+ where: [{
164
+ field: "id",
165
+ value: data.userId
166
+ }]
167
+ })]);
168
+ if (!user || !member) return null;
169
+ return {
170
+ ...member,
171
+ user: {
172
+ id: user.id,
173
+ name: user.name,
174
+ email: user.email,
175
+ image: user.image
176
+ }
177
+ };
178
+ },
179
+ findMemberById: async (memberId) => {
180
+ const adapter = await getCurrentAdapter(baseAdapter);
181
+ const member = await adapter.findOne({
182
+ model: "member",
183
+ where: [{
184
+ field: "id",
185
+ value: memberId
186
+ }]
187
+ });
188
+ if (!member) return null;
189
+ const user = await adapter.findOne({
190
+ model: "user",
191
+ where: [{
192
+ field: "id",
193
+ value: member.userId
194
+ }]
195
+ });
196
+ if (!user) return null;
197
+ return {
198
+ ...member,
199
+ user: {
200
+ id: user.id,
201
+ name: user.name,
202
+ email: user.email,
203
+ image: user.image
204
+ }
205
+ };
206
+ },
207
+ createMember: async (data) => {
208
+ return await (await getCurrentAdapter(baseAdapter)).create({
209
+ model: "member",
210
+ data: {
211
+ ...data,
212
+ createdAt: /* @__PURE__ */ new Date()
213
+ }
214
+ });
215
+ },
216
+ updateMember: async (memberId, role) => {
217
+ return await (await getCurrentAdapter(baseAdapter)).update({
218
+ model: "member",
219
+ where: [{
220
+ field: "id",
221
+ value: memberId
222
+ }],
223
+ update: { role }
224
+ });
225
+ },
226
+ deleteMember: async ({ memberId, organizationId, userId: _userId }) => {
227
+ const adapter = await getCurrentAdapter(baseAdapter);
228
+ let userId;
229
+ if (!_userId) {
230
+ const member$1 = await adapter.findOne({
231
+ model: "member",
232
+ where: [{
233
+ field: "id",
234
+ value: memberId
235
+ }]
236
+ });
237
+ if (!member$1) throw new PayvoAuthError("Member not found");
238
+ userId = member$1.userId;
239
+ } else userId = _userId;
240
+ const member = await adapter.delete({
241
+ model: "member",
242
+ where: [{
243
+ field: "id",
244
+ value: memberId
245
+ }]
246
+ });
247
+ if (options?.teams?.enabled) {
248
+ const teams = await adapter.findMany({
249
+ model: "team",
250
+ where: [{
251
+ field: "organizationId",
252
+ value: organizationId
253
+ }]
254
+ });
255
+ await Promise.all(teams.map((team) => adapter.deleteMany({
256
+ model: "teamMember",
257
+ where: [{
258
+ field: "teamId",
259
+ value: team.id
260
+ }, {
261
+ field: "userId",
262
+ value: userId
263
+ }]
264
+ })));
265
+ }
266
+ return member;
267
+ },
268
+ updateOrganization: async (organizationId, data) => {
269
+ const organization$1 = await (await getCurrentAdapter(baseAdapter)).update({
270
+ model: "organization",
271
+ where: [{
272
+ field: "id",
273
+ value: organizationId
274
+ }],
275
+ update: {
276
+ ...data,
277
+ metadata: typeof data.metadata === "object" ? JSON.stringify(data.metadata) : data.metadata
278
+ }
279
+ });
280
+ if (!organization$1) return null;
281
+ return {
282
+ ...organization$1,
283
+ metadata: organization$1.metadata ? parser_default(organization$1.metadata) : void 0
284
+ };
285
+ },
286
+ deleteOrganization: async (organizationId) => {
287
+ const adapter = await getCurrentAdapter(baseAdapter);
288
+ await adapter.delete({
289
+ model: "member",
290
+ where: [{
291
+ field: "organizationId",
292
+ value: organizationId
293
+ }]
294
+ });
295
+ await adapter.delete({
296
+ model: "invitation",
297
+ where: [{
298
+ field: "organizationId",
299
+ value: organizationId
300
+ }]
301
+ });
302
+ await adapter.delete({
303
+ model: "organization",
304
+ where: [{
305
+ field: "id",
306
+ value: organizationId
307
+ }]
308
+ });
309
+ return organizationId;
310
+ },
311
+ setActiveOrganization: async (sessionToken, organizationId, ctx) => {
312
+ return await context.internalAdapter.updateSession(sessionToken, { activeOrganizationId: organizationId });
313
+ },
314
+ findOrganizationById: async (organizationId) => {
315
+ return await (await getCurrentAdapter(baseAdapter)).findOne({
316
+ model: "organization",
317
+ where: [{
318
+ field: "id",
319
+ value: organizationId
320
+ }]
321
+ });
322
+ },
323
+ checkMembership: async ({ userId, organizationId }) => {
324
+ return await (await getCurrentAdapter(baseAdapter)).findOne({
325
+ model: "member",
326
+ where: [{
327
+ field: "userId",
328
+ value: userId
329
+ }, {
330
+ field: "organizationId",
331
+ value: organizationId
332
+ }]
333
+ });
334
+ },
335
+ findFullOrganization: async ({ organizationId, isSlug, includeTeams, membersLimit }) => {
336
+ const adapter = await getCurrentAdapter(baseAdapter);
337
+ const org = await adapter.findOne({
338
+ model: "organization",
339
+ where: [{
340
+ field: isSlug ? "slug" : "id",
341
+ value: organizationId
342
+ }]
343
+ });
344
+ if (!org) return null;
345
+ const [invitations, members, teams] = await Promise.all([
346
+ adapter.findMany({
347
+ model: "invitation",
348
+ where: [{
349
+ field: "organizationId",
350
+ value: org.id
351
+ }]
352
+ }),
353
+ adapter.findMany({
354
+ model: "member",
355
+ where: [{
356
+ field: "organizationId",
357
+ value: org.id
358
+ }],
359
+ limit: membersLimit ?? options?.membershipLimit ?? 100
360
+ }),
361
+ includeTeams ? adapter.findMany({
362
+ model: "team",
363
+ where: [{
364
+ field: "organizationId",
365
+ value: org.id
366
+ }]
367
+ }) : null
368
+ ]);
369
+ if (!org) return null;
370
+ const userIds = members.map((member) => member.userId);
371
+ const users = userIds.length > 0 ? await adapter.findMany({
372
+ model: "user",
373
+ where: [{
374
+ field: "id",
375
+ value: userIds,
376
+ operator: "in"
377
+ }],
378
+ limit: options?.membershipLimit || 100
379
+ }) : [];
380
+ const userMap = new Map(users.map((user) => [user.id, user]));
381
+ const membersWithUsers = members.map((member) => {
382
+ const user = userMap.get(member.userId);
383
+ if (!user) throw new PayvoAuthError("Unexpected error: User not found for member");
384
+ return {
385
+ ...member,
386
+ user: {
387
+ id: user.id,
388
+ name: user.name,
389
+ email: user.email,
390
+ image: user.image
391
+ }
392
+ };
393
+ });
394
+ return {
395
+ ...org,
396
+ invitations,
397
+ members: membersWithUsers,
398
+ teams
399
+ };
400
+ },
401
+ listOrganizations: async (userId) => {
402
+ const adapter = await getCurrentAdapter(baseAdapter);
403
+ const members = await adapter.findMany({
404
+ model: "member",
405
+ where: [{
406
+ field: "userId",
407
+ value: userId
408
+ }]
409
+ });
410
+ if (!members || members.length === 0) return [];
411
+ const organizationIds = members.map((member) => member.organizationId);
412
+ return await adapter.findMany({
413
+ model: "organization",
414
+ where: [{
415
+ field: "id",
416
+ value: organizationIds,
417
+ operator: "in"
418
+ }]
419
+ });
420
+ },
421
+ createTeam: async (data) => {
422
+ return await (await getCurrentAdapter(baseAdapter)).create({
423
+ model: "team",
424
+ data
425
+ });
426
+ },
427
+ findTeamById: async ({ teamId, organizationId, includeTeamMembers }) => {
428
+ const adapter = await getCurrentAdapter(baseAdapter);
429
+ const team = await adapter.findOne({
430
+ model: "team",
431
+ where: [{
432
+ field: "id",
433
+ value: teamId
434
+ }, ...organizationId ? [{
435
+ field: "organizationId",
436
+ value: organizationId
437
+ }] : []]
438
+ });
439
+ if (!team) return null;
440
+ let members = [];
441
+ if (includeTeamMembers) {
442
+ members = await adapter.findMany({
443
+ model: "teamMember",
444
+ where: [{
445
+ field: "teamId",
446
+ value: teamId
447
+ }],
448
+ limit: options?.membershipLimit || 100
449
+ });
450
+ return {
451
+ ...team,
452
+ members
453
+ };
454
+ }
455
+ return team;
456
+ },
457
+ updateTeam: async (teamId, data) => {
458
+ const adapter = await getCurrentAdapter(baseAdapter);
459
+ if ("id" in data) data.id = void 0;
460
+ return await adapter.update({
461
+ model: "team",
462
+ where: [{
463
+ field: "id",
464
+ value: teamId
465
+ }],
466
+ update: { ...data }
467
+ });
468
+ },
469
+ deleteTeam: async (teamId) => {
470
+ const adapter = await getCurrentAdapter(baseAdapter);
471
+ await adapter.deleteMany({
472
+ model: "teamMember",
473
+ where: [{
474
+ field: "teamId",
475
+ value: teamId
476
+ }]
477
+ });
478
+ return await adapter.delete({
479
+ model: "team",
480
+ where: [{
481
+ field: "id",
482
+ value: teamId
483
+ }]
484
+ });
485
+ },
486
+ listTeams: async (organizationId) => {
487
+ return await (await getCurrentAdapter(baseAdapter)).findMany({
488
+ model: "team",
489
+ where: [{
490
+ field: "organizationId",
491
+ value: organizationId
492
+ }]
493
+ });
494
+ },
495
+ createTeamInvitation: async ({ email, role, teamId, organizationId, inviterId, expiresIn = 1e3 * 60 * 60 * 48 }) => {
496
+ const adapter = await getCurrentAdapter(baseAdapter);
497
+ const expiresAt = getDate(expiresIn);
498
+ return await adapter.create({
499
+ model: "invitation",
500
+ data: {
501
+ email,
502
+ role,
503
+ organizationId,
504
+ teamId,
505
+ inviterId,
506
+ status: "pending",
507
+ expiresAt
508
+ }
509
+ });
510
+ },
511
+ setActiveTeam: async (sessionToken, teamId, ctx) => {
512
+ return await context.internalAdapter.updateSession(sessionToken, { activeTeamId: teamId });
513
+ },
514
+ listTeamMembers: async (data) => {
515
+ return await (await getCurrentAdapter(baseAdapter)).findMany({
516
+ model: "teamMember",
517
+ where: [{
518
+ field: "teamId",
519
+ value: data.teamId
520
+ }]
521
+ });
522
+ },
523
+ countTeamMembers: async (data) => {
524
+ return await (await getCurrentAdapter(baseAdapter)).count({
525
+ model: "teamMember",
526
+ where: [{
527
+ field: "teamId",
528
+ value: data.teamId
529
+ }]
530
+ });
531
+ },
532
+ countMembers: async (data) => {
533
+ return await (await getCurrentAdapter(baseAdapter)).count({
534
+ model: "member",
535
+ where: [{
536
+ field: "organizationId",
537
+ value: data.organizationId
538
+ }]
539
+ });
540
+ },
541
+ listTeamsByUser: async (data) => {
542
+ const adapter = await getCurrentAdapter(baseAdapter);
543
+ const members = await adapter.findMany({
544
+ model: "teamMember",
545
+ where: [{
546
+ field: "userId",
547
+ value: data.userId
548
+ }]
549
+ });
550
+ return await adapter.findMany({
551
+ model: "team",
552
+ where: [{
553
+ field: "id",
554
+ operator: "in",
555
+ value: members.map((m) => m.teamId)
556
+ }]
557
+ });
558
+ },
559
+ findTeamMember: async (data) => {
560
+ return await (await getCurrentAdapter(baseAdapter)).findOne({
561
+ model: "teamMember",
562
+ where: [{
563
+ field: "teamId",
564
+ value: data.teamId
565
+ }, {
566
+ field: "userId",
567
+ value: data.userId
568
+ }]
569
+ });
570
+ },
571
+ findOrCreateTeamMember: async (data) => {
572
+ const adapter = await getCurrentAdapter(baseAdapter);
573
+ const member = await adapter.findOne({
574
+ model: "teamMember",
575
+ where: [{
576
+ field: "teamId",
577
+ value: data.teamId
578
+ }, {
579
+ field: "userId",
580
+ value: data.userId
581
+ }]
582
+ });
583
+ if (member) return member;
584
+ return await adapter.create({
585
+ model: "teamMember",
586
+ data: {
587
+ teamId: data.teamId,
588
+ userId: data.userId,
589
+ createdAt: /* @__PURE__ */ new Date()
590
+ }
591
+ });
592
+ },
593
+ removeTeamMember: async (data) => {
594
+ await (await getCurrentAdapter(baseAdapter)).deleteMany({
595
+ model: "teamMember",
596
+ where: [{
597
+ field: "teamId",
598
+ value: data.teamId
599
+ }, {
600
+ field: "userId",
601
+ value: data.userId
602
+ }]
603
+ });
604
+ },
605
+ findInvitationsByTeamId: async (teamId) => {
606
+ return await (await getCurrentAdapter(baseAdapter)).findMany({
607
+ model: "invitation",
608
+ where: [{
609
+ field: "teamId",
610
+ value: teamId
611
+ }]
612
+ });
613
+ },
614
+ listUserInvitations: async (email) => {
615
+ return await (await getCurrentAdapter(baseAdapter)).findMany({
616
+ model: "invitation",
617
+ where: [{
618
+ field: "email",
619
+ value: email.toLowerCase()
620
+ }]
621
+ });
622
+ },
623
+ createInvitation: async ({ invitation, user }) => {
624
+ const adapter = await getCurrentAdapter(baseAdapter);
625
+ const expiresAt = getDate(options?.invitationExpiresIn || 3600 * 48, "sec");
626
+ return await adapter.create({
627
+ model: "invitation",
628
+ data: {
629
+ status: "pending",
630
+ expiresAt,
631
+ createdAt: /* @__PURE__ */ new Date(),
632
+ inviterId: user.id,
633
+ ...invitation,
634
+ teamId: invitation.teamIds.length > 0 ? invitation.teamIds.join(",") : null
635
+ }
636
+ });
637
+ },
638
+ findInvitationById: async (id) => {
639
+ return await (await getCurrentAdapter(baseAdapter)).findOne({
640
+ model: "invitation",
641
+ where: [{
642
+ field: "id",
643
+ value: id
644
+ }]
645
+ });
646
+ },
647
+ findPendingInvitation: async (data) => {
648
+ return (await (await getCurrentAdapter(baseAdapter)).findMany({
649
+ model: "invitation",
650
+ where: [
651
+ {
652
+ field: "email",
653
+ value: data.email.toLowerCase()
654
+ },
655
+ {
656
+ field: "organizationId",
657
+ value: data.organizationId
658
+ },
659
+ {
660
+ field: "status",
661
+ value: "pending"
662
+ }
663
+ ]
664
+ })).filter((invite) => new Date(invite.expiresAt) > /* @__PURE__ */ new Date());
665
+ },
666
+ findPendingInvitations: async (data) => {
667
+ return (await (await getCurrentAdapter(baseAdapter)).findMany({
668
+ model: "invitation",
669
+ where: [{
670
+ field: "organizationId",
671
+ value: data.organizationId
672
+ }, {
673
+ field: "status",
674
+ value: "pending"
675
+ }]
676
+ })).filter((invite) => new Date(invite.expiresAt) > /* @__PURE__ */ new Date());
677
+ },
678
+ listInvitations: async (data) => {
679
+ return await (await getCurrentAdapter(baseAdapter)).findMany({
680
+ model: "invitation",
681
+ where: [{
682
+ field: "organizationId",
683
+ value: data.organizationId
684
+ }]
685
+ });
686
+ },
687
+ updateInvitation: async (data) => {
688
+ return await (await getCurrentAdapter(baseAdapter)).update({
689
+ model: "invitation",
690
+ where: [{
691
+ field: "id",
692
+ value: data.invitationId
693
+ }],
694
+ update: { status: data.status }
695
+ });
696
+ }
697
+ };
698
+ };
699
+
700
+ //#endregion
701
+ //#region src/plugins/organization/call.ts
702
+ const orgMiddleware = createAuthMiddleware(async () => {
703
+ return {};
704
+ });
705
+ /**
706
+ * The middleware forces the endpoint to require a valid session by utilizing the `sessionMiddleware`.
707
+ * It also appends additional types to the session type regarding organizations.
708
+ */
709
+ const orgSessionMiddleware = createAuthMiddleware({ use: [sessionMiddleware] }, async (ctx) => {
710
+ return { session: ctx.context.session };
711
+ });
712
+
713
+ //#endregion
714
+ //#region src/plugins/organization/error-codes.ts
715
+ const ORGANIZATION_ERROR_CODES = defineErrorCodes({
716
+ YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_ORGANIZATION: "You are not allowed to create a new organization",
717
+ YOU_HAVE_REACHED_THE_MAXIMUM_NUMBER_OF_ORGANIZATIONS: "You have reached the maximum number of organizations",
718
+ ORGANIZATION_ALREADY_EXISTS: "Organization already exists",
719
+ ORGANIZATION_SLUG_ALREADY_TAKEN: "Organization slug already taken",
720
+ ORGANIZATION_NOT_FOUND: "Organization not found",
721
+ USER_IS_NOT_A_MEMBER_OF_THE_ORGANIZATION: "User is not a member of the organization",
722
+ YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_ORGANIZATION: "You are not allowed to update this organization",
723
+ YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_ORGANIZATION: "You are not allowed to delete this organization",
724
+ NO_ACTIVE_ORGANIZATION: "No active organization",
725
+ USER_IS_ALREADY_A_MEMBER_OF_THIS_ORGANIZATION: "User is already a member of this organization",
726
+ MEMBER_NOT_FOUND: "Member not found",
727
+ ROLE_NOT_FOUND: "Role not found",
728
+ YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_TEAM: "You are not allowed to create a new team",
729
+ TEAM_ALREADY_EXISTS: "Team already exists",
730
+ TEAM_NOT_FOUND: "Team not found",
731
+ YOU_CANNOT_LEAVE_THE_ORGANIZATION_AS_THE_ONLY_OWNER: "You cannot leave the organization as the only owner",
732
+ YOU_CANNOT_LEAVE_THE_ORGANIZATION_WITHOUT_AN_OWNER: "You cannot leave the organization without an owner",
733
+ YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_MEMBER: "You are not allowed to delete this member",
734
+ YOU_ARE_NOT_ALLOWED_TO_INVITE_USERS_TO_THIS_ORGANIZATION: "You are not allowed to invite users to this organization",
735
+ USER_IS_ALREADY_INVITED_TO_THIS_ORGANIZATION: "User is already invited to this organization",
736
+ INVITATION_NOT_FOUND: "Invitation not found",
737
+ YOU_ARE_NOT_THE_RECIPIENT_OF_THE_INVITATION: "You are not the recipient of the invitation",
738
+ EMAIL_VERIFICATION_REQUIRED_BEFORE_ACCEPTING_OR_REJECTING_INVITATION: "Email verification required before accepting or rejecting invitation",
739
+ YOU_ARE_NOT_ALLOWED_TO_CANCEL_THIS_INVITATION: "You are not allowed to cancel this invitation",
740
+ INVITER_IS_NO_LONGER_A_MEMBER_OF_THE_ORGANIZATION: "Inviter is no longer a member of the organization",
741
+ YOU_ARE_NOT_ALLOWED_TO_INVITE_USER_WITH_THIS_ROLE: "You are not allowed to invite a user with this role",
742
+ FAILED_TO_RETRIEVE_INVITATION: "Failed to retrieve invitation",
743
+ YOU_HAVE_REACHED_THE_MAXIMUM_NUMBER_OF_TEAMS: "You have reached the maximum number of teams",
744
+ UNABLE_TO_REMOVE_LAST_TEAM: "Unable to remove last team",
745
+ YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_MEMBER: "You are not allowed to update this member",
746
+ ORGANIZATION_MEMBERSHIP_LIMIT_REACHED: "Organization membership limit reached",
747
+ YOU_ARE_NOT_ALLOWED_TO_CREATE_TEAMS_IN_THIS_ORGANIZATION: "You are not allowed to create teams in this organization",
748
+ YOU_ARE_NOT_ALLOWED_TO_DELETE_TEAMS_IN_THIS_ORGANIZATION: "You are not allowed to delete teams in this organization",
749
+ YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_TEAM: "You are not allowed to update this team",
750
+ YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_TEAM: "You are not allowed to delete this team",
751
+ INVITATION_LIMIT_REACHED: "Invitation limit reached",
752
+ TEAM_MEMBER_LIMIT_REACHED: "Team member limit reached",
753
+ USER_IS_NOT_A_MEMBER_OF_THE_TEAM: "User is not a member of the team",
754
+ YOU_CAN_NOT_ACCESS_THE_MEMBERS_OF_THIS_TEAM: "You are not allowed to list the members of this team",
755
+ YOU_DO_NOT_HAVE_AN_ACTIVE_TEAM: "You do not have an active team",
756
+ YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_TEAM_MEMBER: "You are not allowed to create a new member",
757
+ YOU_ARE_NOT_ALLOWED_TO_REMOVE_A_TEAM_MEMBER: "You are not allowed to remove a team member",
758
+ YOU_ARE_NOT_ALLOWED_TO_ACCESS_THIS_ORGANIZATION: "You are not allowed to access this organization as an owner",
759
+ YOU_ARE_NOT_A_MEMBER_OF_THIS_ORGANIZATION: "You are not a member of this organization",
760
+ MISSING_AC_INSTANCE: "Dynamic Access Control requires a pre-defined ac instance on the server auth plugin. Read server logs for more information",
761
+ YOU_MUST_BE_IN_AN_ORGANIZATION_TO_CREATE_A_ROLE: "You must be in an organization to create a role",
762
+ YOU_ARE_NOT_ALLOWED_TO_CREATE_A_ROLE: "You are not allowed to create a role",
763
+ YOU_ARE_NOT_ALLOWED_TO_UPDATE_A_ROLE: "You are not allowed to update a role",
764
+ YOU_ARE_NOT_ALLOWED_TO_DELETE_A_ROLE: "You are not allowed to delete a role",
765
+ YOU_ARE_NOT_ALLOWED_TO_READ_A_ROLE: "You are not allowed to read a role",
766
+ YOU_ARE_NOT_ALLOWED_TO_LIST_A_ROLE: "You are not allowed to list a role",
767
+ YOU_ARE_NOT_ALLOWED_TO_GET_A_ROLE: "You are not allowed to get a role",
768
+ TOO_MANY_ROLES: "This organization has too many roles",
769
+ INVALID_RESOURCE: "The provided permission includes an invalid resource",
770
+ ROLE_NAME_IS_ALREADY_TAKEN: "That role name is already taken",
771
+ CANNOT_DELETE_A_PRE_DEFINED_ROLE: "Cannot delete a pre-defined role"
772
+ });
773
+
774
+ //#endregion
775
+ //#region src/plugins/organization/has-permission.ts
776
+ const hasPermission = async (input, ctx) => {
777
+ let acRoles = { ...input.options.roles || defaultRoles };
778
+ if (ctx && input.organizationId && input.options.dynamicAccessControl?.enabled && input.options.ac && !input.useMemoryCache) {
779
+ const roles = await ctx.context.adapter.findMany({
780
+ model: "organizationRole",
781
+ where: [{
782
+ field: "organizationId",
783
+ value: input.organizationId
784
+ }]
785
+ });
786
+ for (const { role, permission: permissionsString } of roles) {
787
+ if (role in acRoles) continue;
788
+ const result = z$1.record(z$1.string(), z$1.array(z$1.string())).safeParse(JSON.parse(permissionsString));
789
+ if (!result.success) {
790
+ ctx.context.logger.error("[hasPermission] Invalid permissions for role " + role, { permissions: JSON.parse(permissionsString) });
791
+ throw new APIError$1("INTERNAL_SERVER_ERROR", { message: "Invalid permissions for role " + role });
792
+ }
793
+ acRoles[role] = input.options.ac.newRole(result.data);
794
+ }
795
+ }
796
+ if (input.useMemoryCache) acRoles = cacheAllRoles.get(input.organizationId) || acRoles;
797
+ cacheAllRoles.set(input.organizationId, acRoles);
798
+ return hasPermissionFn(input, acRoles);
799
+ };
800
+
801
+ //#endregion
802
+ //#region src/plugins/organization/routes/crud-access-control.ts
803
+ const normalizeRoleName = (role) => role.toLowerCase();
804
+ const DEFAULT_MAXIMUM_ROLES_PER_ORGANIZATION = Number.POSITIVE_INFINITY;
805
+ const getAdditionalFields = (options, shouldBePartial = false) => {
806
+ let additionalFields = options?.schema?.organizationRole?.additionalFields || {};
807
+ if (shouldBePartial) for (const key in additionalFields) additionalFields[key].required = false;
808
+ return {
809
+ additionalFieldsSchema: toZodSchema({
810
+ fields: additionalFields,
811
+ isClientSide: true
812
+ }),
813
+ $AdditionalFields: {},
814
+ $ReturnAdditionalFields: {}
815
+ };
816
+ };
817
+ const createOrgRole = (options) => {
818
+ const { additionalFieldsSchema, $AdditionalFields, $ReturnAdditionalFields } = getAdditionalFields(options, false);
819
+ return createAuthEndpoint("/organization/create-role", {
820
+ method: "POST",
821
+ body: z$1.object({
822
+ organizationId: z$1.string().optional().meta({ description: "The id of the organization to create the role in. If not provided, the user's active organization will be used." }),
823
+ role: z$1.string().meta({ description: "The name of the role to create" }),
824
+ permission: z$1.record(z$1.string(), z$1.array(z$1.string())).meta({ description: "The permission to assign to the role" }),
825
+ additionalFields: z$1.object({ ...additionalFieldsSchema.shape }).optional()
826
+ }),
827
+ metadata: { $Infer: { body: {} } },
828
+ requireHeaders: true,
829
+ use: [orgSessionMiddleware]
830
+ }, async (ctx) => {
831
+ const { session, user } = ctx.context.session;
832
+ let roleName = ctx.body.role;
833
+ const permission = ctx.body.permission;
834
+ const additionalFields = ctx.body.additionalFields;
835
+ const ac = options.ac;
836
+ if (!ac) {
837
+ ctx.context.logger.error(`[Dynamic Access Control] The organization plugin is missing a pre-defined ac instance.`, `\nPlease refer to the documentation here: https://payvopayvo.com/docs/plugins/organization#dynamic-access-control`);
838
+ throw new APIError$1("NOT_IMPLEMENTED", { message: ORGANIZATION_ERROR_CODES.MISSING_AC_INSTANCE });
839
+ }
840
+ const organizationId = ctx.body.organizationId ?? session.activeOrganizationId;
841
+ if (!organizationId) {
842
+ ctx.context.logger.error(`[Dynamic Access Control] The session is missing an active organization id to create a role. Either set an active org id, or pass an organizationId in the request body.`);
843
+ throw new APIError$1("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.YOU_MUST_BE_IN_AN_ORGANIZATION_TO_CREATE_A_ROLE });
844
+ }
845
+ roleName = normalizeRoleName(roleName);
846
+ await checkIfRoleNameIsTakenByPreDefinedRole({
847
+ role: roleName,
848
+ organizationId,
849
+ options,
850
+ ctx
851
+ });
852
+ const member = await ctx.context.adapter.findOne({
853
+ model: "member",
854
+ where: [{
855
+ field: "organizationId",
856
+ value: organizationId,
857
+ operator: "eq",
858
+ connector: "AND"
859
+ }, {
860
+ field: "userId",
861
+ value: user.id,
862
+ operator: "eq",
863
+ connector: "AND"
864
+ }]
865
+ });
866
+ if (!member) {
867
+ ctx.context.logger.error(`[Dynamic Access Control] The user is not a member of the organization to create a role.`, {
868
+ userId: user.id,
869
+ organizationId
870
+ });
871
+ throw new APIError$1("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_A_MEMBER_OF_THIS_ORGANIZATION });
872
+ }
873
+ if (!await hasPermission({
874
+ options,
875
+ organizationId,
876
+ permissions: { ac: ["create"] },
877
+ role: member.role
878
+ }, ctx)) {
879
+ ctx.context.logger.error(`[Dynamic Access Control] The user is not permitted to create a role. If this is unexpected, please make sure the role associated to that member has the "ac" resource with the "create" permission.`, {
880
+ userId: user.id,
881
+ organizationId,
882
+ role: member.role
883
+ });
884
+ throw new APIError$1("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_CREATE_A_ROLE });
885
+ }
886
+ const maximumRolesPerOrganization = typeof options.dynamicAccessControl?.maximumRolesPerOrganization === "function" ? await options.dynamicAccessControl.maximumRolesPerOrganization(organizationId) : options.dynamicAccessControl?.maximumRolesPerOrganization ?? DEFAULT_MAXIMUM_ROLES_PER_ORGANIZATION;
887
+ const rolesInDB = await ctx.context.adapter.count({
888
+ model: "organizationRole",
889
+ where: [{
890
+ field: "organizationId",
891
+ value: organizationId,
892
+ operator: "eq",
893
+ connector: "AND"
894
+ }]
895
+ });
896
+ if (rolesInDB >= maximumRolesPerOrganization) {
897
+ ctx.context.logger.error(`[Dynamic Access Control] Failed to create a new role, the organization has too many roles. Maximum allowed roles is ${maximumRolesPerOrganization}.`, {
898
+ organizationId,
899
+ maximumRolesPerOrganization,
900
+ rolesInDB
901
+ });
902
+ throw new APIError$1("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.TOO_MANY_ROLES });
903
+ }
904
+ await checkForInvalidResources({
905
+ ac,
906
+ ctx,
907
+ permission
908
+ });
909
+ await checkIfMemberHasPermission({
910
+ ctx,
911
+ member,
912
+ options,
913
+ organizationId,
914
+ permissionRequired: permission,
915
+ user,
916
+ action: "create"
917
+ });
918
+ await checkIfRoleNameIsTakenByRoleInDB({
919
+ ctx,
920
+ organizationId,
921
+ role: roleName
922
+ });
923
+ const newRole = ac.newRole(permission);
924
+ const data = {
925
+ ...await ctx.context.adapter.create({
926
+ model: "organizationRole",
927
+ data: {
928
+ createdAt: /* @__PURE__ */ new Date(),
929
+ organizationId,
930
+ permission: JSON.stringify(permission),
931
+ role: roleName,
932
+ ...additionalFields
933
+ }
934
+ }),
935
+ permission
936
+ };
937
+ return ctx.json({
938
+ success: true,
939
+ roleData: data,
940
+ statements: newRole.statements
941
+ });
942
+ });
943
+ };
944
+ const deleteOrgRole = (options) => {
945
+ return createAuthEndpoint("/organization/delete-role", {
946
+ method: "POST",
947
+ body: z$1.object({ organizationId: z$1.string().optional().meta({ description: "The id of the organization to create the role in. If not provided, the user's active organization will be used." }) }).and(z$1.union([z$1.object({ roleName: z$1.string().nonempty().meta({ description: "The name of the role to delete" }) }), z$1.object({ roleId: z$1.string().nonempty().meta({ description: "The id of the role to delete" }) })])),
948
+ requireHeaders: true,
949
+ use: [orgSessionMiddleware],
950
+ metadata: { $Infer: { body: {} } }
951
+ }, async (ctx) => {
952
+ const { session, user } = ctx.context.session;
953
+ const organizationId = ctx.body.organizationId ?? session.activeOrganizationId;
954
+ if (!organizationId) {
955
+ ctx.context.logger.error(`[Dynamic Access Control] The session is missing an active organization id to delete a role. Either set an active org id, or pass an organizationId in the request body.`);
956
+ throw new APIError$1("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.NO_ACTIVE_ORGANIZATION });
957
+ }
958
+ const member = await ctx.context.adapter.findOne({
959
+ model: "member",
960
+ where: [{
961
+ field: "organizationId",
962
+ value: organizationId,
963
+ operator: "eq",
964
+ connector: "AND"
965
+ }, {
966
+ field: "userId",
967
+ value: user.id,
968
+ operator: "eq",
969
+ connector: "AND"
970
+ }]
971
+ });
972
+ if (!member) {
973
+ ctx.context.logger.error(`[Dynamic Access Control] The user is not a member of the organization to delete a role.`, {
974
+ userId: user.id,
975
+ organizationId
976
+ });
977
+ throw new APIError$1("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_A_MEMBER_OF_THIS_ORGANIZATION });
978
+ }
979
+ if (!await hasPermission({
980
+ options,
981
+ organizationId,
982
+ permissions: { ac: ["delete"] },
983
+ role: member.role
984
+ }, ctx)) {
985
+ ctx.context.logger.error(`[Dynamic Access Control] The user is not permitted to delete a role. If this is unexpected, please make sure the role associated to that member has the "ac" resource with the "delete" permission.`, {
986
+ userId: user.id,
987
+ organizationId,
988
+ role: member.role
989
+ });
990
+ throw new APIError$1("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_DELETE_A_ROLE });
991
+ }
992
+ if (ctx.body.roleName) {
993
+ const roleName = ctx.body.roleName;
994
+ const defaultRoles$2 = options.roles ? Object.keys(options.roles) : [
995
+ "owner",
996
+ "admin",
997
+ "member"
998
+ ];
999
+ if (defaultRoles$2.includes(roleName)) {
1000
+ ctx.context.logger.error(`[Dynamic Access Control] Cannot delete a pre-defined role.`, {
1001
+ roleName,
1002
+ organizationId,
1003
+ defaultRoles: defaultRoles$2
1004
+ });
1005
+ throw new APIError$1("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.CANNOT_DELETE_A_PRE_DEFINED_ROLE });
1006
+ }
1007
+ }
1008
+ let condition;
1009
+ if (ctx.body.roleName) condition = {
1010
+ field: "role",
1011
+ value: ctx.body.roleName,
1012
+ operator: "eq",
1013
+ connector: "AND"
1014
+ };
1015
+ else if (ctx.body.roleId) condition = {
1016
+ field: "id",
1017
+ value: ctx.body.roleId,
1018
+ operator: "eq",
1019
+ connector: "AND"
1020
+ };
1021
+ else {
1022
+ ctx.context.logger.error(`[Dynamic Access Control] The role name/id is not provided in the request body.`);
1023
+ throw new APIError$1("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ROLE_NOT_FOUND });
1024
+ }
1025
+ const existingRoleInDB = await ctx.context.adapter.findOne({
1026
+ model: "organizationRole",
1027
+ where: [{
1028
+ field: "organizationId",
1029
+ value: organizationId,
1030
+ operator: "eq",
1031
+ connector: "AND"
1032
+ }, condition]
1033
+ });
1034
+ if (!existingRoleInDB) {
1035
+ ctx.context.logger.error(`[Dynamic Access Control] The role name/id does not exist in the database.`, {
1036
+ ..."roleName" in ctx.body ? { roleName: ctx.body.roleName } : { roleId: ctx.body.roleId },
1037
+ organizationId
1038
+ });
1039
+ throw new APIError$1("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ROLE_NOT_FOUND });
1040
+ }
1041
+ existingRoleInDB.permission = JSON.parse(existingRoleInDB.permission);
1042
+ await ctx.context.adapter.delete({
1043
+ model: "organizationRole",
1044
+ where: [{
1045
+ field: "organizationId",
1046
+ value: organizationId,
1047
+ operator: "eq",
1048
+ connector: "AND"
1049
+ }, condition]
1050
+ });
1051
+ return ctx.json({ success: true });
1052
+ });
1053
+ };
1054
+ const listOrgRoles = (options) => {
1055
+ const { $ReturnAdditionalFields } = getAdditionalFields(options, false);
1056
+ return createAuthEndpoint("/organization/list-roles", {
1057
+ method: "GET",
1058
+ use: [orgSessionMiddleware],
1059
+ query: z$1.object({ organizationId: z$1.string().optional().meta({ description: "The id of the organization to list roles for. If not provided, the user's active organization will be used." }) }).optional()
1060
+ }, async (ctx) => {
1061
+ const { session, user } = ctx.context.session;
1062
+ const organizationId = ctx.query?.organizationId ?? session.activeOrganizationId;
1063
+ if (!organizationId) {
1064
+ ctx.context.logger.error(`[Dynamic Access Control] The session is missing an active organization id to list roles. Either set an active org id, or pass an organizationId in the request query.`);
1065
+ throw new APIError$1("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.NO_ACTIVE_ORGANIZATION });
1066
+ }
1067
+ const member = await ctx.context.adapter.findOne({
1068
+ model: "member",
1069
+ where: [{
1070
+ field: "organizationId",
1071
+ value: organizationId,
1072
+ operator: "eq",
1073
+ connector: "AND"
1074
+ }, {
1075
+ field: "userId",
1076
+ value: user.id,
1077
+ operator: "eq",
1078
+ connector: "AND"
1079
+ }]
1080
+ });
1081
+ if (!member) {
1082
+ ctx.context.logger.error(`[Dynamic Access Control] The user is not a member of the organization to list roles.`, {
1083
+ userId: user.id,
1084
+ organizationId
1085
+ });
1086
+ throw new APIError$1("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_A_MEMBER_OF_THIS_ORGANIZATION });
1087
+ }
1088
+ if (!await hasPermission({
1089
+ options,
1090
+ organizationId,
1091
+ permissions: { ac: ["read"] },
1092
+ role: member.role
1093
+ }, ctx)) {
1094
+ ctx.context.logger.error(`[Dynamic Access Control] The user is not permitted to list roles.`, {
1095
+ userId: user.id,
1096
+ organizationId,
1097
+ role: member.role
1098
+ });
1099
+ throw new APIError$1("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_LIST_A_ROLE });
1100
+ }
1101
+ let roles = await ctx.context.adapter.findMany({
1102
+ model: "organizationRole",
1103
+ where: [{
1104
+ field: "organizationId",
1105
+ value: organizationId,
1106
+ operator: "eq",
1107
+ connector: "AND"
1108
+ }]
1109
+ });
1110
+ roles = roles.map((x) => ({
1111
+ ...x,
1112
+ permission: JSON.parse(x.permission)
1113
+ }));
1114
+ return ctx.json(roles);
1115
+ });
1116
+ };
1117
+ const getOrgRole = (options) => {
1118
+ const { $ReturnAdditionalFields } = getAdditionalFields(options, false);
1119
+ return createAuthEndpoint("/organization/get-role", {
1120
+ method: "GET",
1121
+ use: [orgSessionMiddleware],
1122
+ query: z$1.object({ organizationId: z$1.string().optional().meta({ description: "The id of the organization to read a role for. If not provided, the user's active organization will be used." }) }).and(z$1.union([z$1.object({ roleName: z$1.string().nonempty().meta({ description: "The name of the role to read" }) }), z$1.object({ roleId: z$1.string().nonempty().meta({ description: "The id of the role to read" }) })])).optional(),
1123
+ metadata: { $Infer: { query: {} } }
1124
+ }, async (ctx) => {
1125
+ const { session, user } = ctx.context.session;
1126
+ const organizationId = ctx.query?.organizationId ?? session.activeOrganizationId;
1127
+ if (!organizationId) {
1128
+ ctx.context.logger.error(`[Dynamic Access Control] The session is missing an active organization id to read a role. Either set an active org id, or pass an organizationId in the request query.`);
1129
+ throw new APIError$1("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.NO_ACTIVE_ORGANIZATION });
1130
+ }
1131
+ const member = await ctx.context.adapter.findOne({
1132
+ model: "member",
1133
+ where: [{
1134
+ field: "organizationId",
1135
+ value: organizationId,
1136
+ operator: "eq",
1137
+ connector: "AND"
1138
+ }, {
1139
+ field: "userId",
1140
+ value: user.id,
1141
+ operator: "eq",
1142
+ connector: "AND"
1143
+ }]
1144
+ });
1145
+ if (!member) {
1146
+ ctx.context.logger.error(`[Dynamic Access Control] The user is not a member of the organization to read a role.`, {
1147
+ userId: user.id,
1148
+ organizationId
1149
+ });
1150
+ throw new APIError$1("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_A_MEMBER_OF_THIS_ORGANIZATION });
1151
+ }
1152
+ if (!await hasPermission({
1153
+ options,
1154
+ organizationId,
1155
+ permissions: { ac: ["read"] },
1156
+ role: member.role
1157
+ }, ctx)) {
1158
+ ctx.context.logger.error(`[Dynamic Access Control] The user is not permitted to read a role.`, {
1159
+ userId: user.id,
1160
+ organizationId,
1161
+ role: member.role
1162
+ });
1163
+ throw new APIError$1("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_READ_A_ROLE });
1164
+ }
1165
+ let condition;
1166
+ if (ctx.query.roleName) condition = {
1167
+ field: "role",
1168
+ value: ctx.query.roleName,
1169
+ operator: "eq",
1170
+ connector: "AND"
1171
+ };
1172
+ else if (ctx.query.roleId) condition = {
1173
+ field: "id",
1174
+ value: ctx.query.roleId,
1175
+ operator: "eq",
1176
+ connector: "AND"
1177
+ };
1178
+ else {
1179
+ ctx.context.logger.error(`[Dynamic Access Control] The role name/id is not provided in the request query.`);
1180
+ throw new APIError$1("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ROLE_NOT_FOUND });
1181
+ }
1182
+ let role = await ctx.context.adapter.findOne({
1183
+ model: "organizationRole",
1184
+ where: [{
1185
+ field: "organizationId",
1186
+ value: organizationId,
1187
+ operator: "eq",
1188
+ connector: "AND"
1189
+ }, condition]
1190
+ });
1191
+ if (!role) {
1192
+ ctx.context.logger.error(`[Dynamic Access Control] The role name/id does not exist in the database.`, {
1193
+ ..."roleName" in ctx.query ? { roleName: ctx.query.roleName } : { roleId: ctx.query.roleId },
1194
+ organizationId
1195
+ });
1196
+ throw new APIError$1("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ROLE_NOT_FOUND });
1197
+ }
1198
+ role.permission = JSON.parse(role.permission);
1199
+ return ctx.json(role);
1200
+ });
1201
+ };
1202
+ const updateOrgRole = (options) => {
1203
+ const { additionalFieldsSchema, $AdditionalFields, $ReturnAdditionalFields } = getAdditionalFields(options, true);
1204
+ return createAuthEndpoint("/organization/update-role", {
1205
+ method: "POST",
1206
+ body: z$1.object({
1207
+ organizationId: z$1.string().optional().meta({ description: "The id of the organization to update the role in. If not provided, the user's active organization will be used." }),
1208
+ data: z$1.object({
1209
+ permission: z$1.record(z$1.string(), z$1.array(z$1.string())).optional().meta({ description: "The permission to update the role with" }),
1210
+ roleName: z$1.string().optional().meta({ description: "The name of the role to update" }),
1211
+ ...additionalFieldsSchema.shape
1212
+ })
1213
+ }).and(z$1.union([z$1.object({ roleName: z$1.string().nonempty().meta({ description: "The name of the role to update" }) }), z$1.object({ roleId: z$1.string().nonempty().meta({ description: "The id of the role to update" }) })])),
1214
+ metadata: { $Infer: { body: {} } },
1215
+ use: [orgSessionMiddleware]
1216
+ }, async (ctx) => {
1217
+ const { session, user } = ctx.context.session;
1218
+ const ac = options.ac;
1219
+ if (!ac) {
1220
+ ctx.context.logger.error(`[Dynamic Access Control] The organization plugin is missing a pre-defined ac instance.`, `\nPlease refer to the documentation here: https://payvopayvo.com/docs/plugins/organization#dynamic-access-control`);
1221
+ throw new APIError$1("NOT_IMPLEMENTED", { message: ORGANIZATION_ERROR_CODES.MISSING_AC_INSTANCE });
1222
+ }
1223
+ const organizationId = ctx.body.organizationId ?? session.activeOrganizationId;
1224
+ if (!organizationId) {
1225
+ ctx.context.logger.error(`[Dynamic Access Control] The session is missing an active organization id to update a role. Either set an active org id, or pass an organizationId in the request body.`);
1226
+ throw new APIError$1("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.NO_ACTIVE_ORGANIZATION });
1227
+ }
1228
+ const member = await ctx.context.adapter.findOne({
1229
+ model: "member",
1230
+ where: [{
1231
+ field: "organizationId",
1232
+ value: organizationId,
1233
+ operator: "eq",
1234
+ connector: "AND"
1235
+ }, {
1236
+ field: "userId",
1237
+ value: user.id,
1238
+ operator: "eq",
1239
+ connector: "AND"
1240
+ }]
1241
+ });
1242
+ if (!member) {
1243
+ ctx.context.logger.error(`[Dynamic Access Control] The user is not a member of the organization to update a role.`, {
1244
+ userId: user.id,
1245
+ organizationId
1246
+ });
1247
+ throw new APIError$1("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_A_MEMBER_OF_THIS_ORGANIZATION });
1248
+ }
1249
+ if (!await hasPermission({
1250
+ options,
1251
+ organizationId,
1252
+ role: member.role,
1253
+ permissions: { ac: ["update"] }
1254
+ }, ctx)) {
1255
+ ctx.context.logger.error(`[Dynamic Access Control] The user is not permitted to update a role.`);
1256
+ throw new APIError$1("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_UPDATE_A_ROLE });
1257
+ }
1258
+ let condition;
1259
+ if (ctx.body.roleName) condition = {
1260
+ field: "role",
1261
+ value: ctx.body.roleName,
1262
+ operator: "eq",
1263
+ connector: "AND"
1264
+ };
1265
+ else if (ctx.body.roleId) condition = {
1266
+ field: "id",
1267
+ value: ctx.body.roleId,
1268
+ operator: "eq",
1269
+ connector: "AND"
1270
+ };
1271
+ else {
1272
+ ctx.context.logger.error(`[Dynamic Access Control] The role name/id is not provided in the request body.`);
1273
+ throw new APIError$1("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ROLE_NOT_FOUND });
1274
+ }
1275
+ let role = await ctx.context.adapter.findOne({
1276
+ model: "organizationRole",
1277
+ where: [{
1278
+ field: "organizationId",
1279
+ value: organizationId,
1280
+ operator: "eq",
1281
+ connector: "AND"
1282
+ }, condition]
1283
+ });
1284
+ if (!role) {
1285
+ ctx.context.logger.error(`[Dynamic Access Control] The role name/id does not exist in the database.`, {
1286
+ ..."roleName" in ctx.body ? { roleName: ctx.body.roleName } : { roleId: ctx.body.roleId },
1287
+ organizationId
1288
+ });
1289
+ throw new APIError$1("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ROLE_NOT_FOUND });
1290
+ }
1291
+ role.permission = role.permission ? JSON.parse(role.permission) : void 0;
1292
+ const { permission: _, roleName: __,...additionalFields } = ctx.body.data;
1293
+ let updateData = { ...additionalFields };
1294
+ if (ctx.body.data.permission) {
1295
+ let newPermission = ctx.body.data.permission;
1296
+ await checkForInvalidResources({
1297
+ ac,
1298
+ ctx,
1299
+ permission: newPermission
1300
+ });
1301
+ await checkIfMemberHasPermission({
1302
+ ctx,
1303
+ member,
1304
+ options,
1305
+ organizationId,
1306
+ permissionRequired: newPermission,
1307
+ user,
1308
+ action: "update"
1309
+ });
1310
+ updateData.permission = newPermission;
1311
+ }
1312
+ if (ctx.body.data.roleName) {
1313
+ let newRoleName = ctx.body.data.roleName;
1314
+ newRoleName = normalizeRoleName(newRoleName);
1315
+ await checkIfRoleNameIsTakenByPreDefinedRole({
1316
+ role: newRoleName,
1317
+ organizationId,
1318
+ options,
1319
+ ctx
1320
+ });
1321
+ await checkIfRoleNameIsTakenByRoleInDB({
1322
+ role: newRoleName,
1323
+ organizationId,
1324
+ ctx
1325
+ });
1326
+ updateData.role = newRoleName;
1327
+ }
1328
+ const update = {
1329
+ ...updateData,
1330
+ ...updateData.permission ? { permission: JSON.stringify(updateData.permission) } : {}
1331
+ };
1332
+ await ctx.context.adapter.update({
1333
+ model: "organizationRole",
1334
+ where: [{
1335
+ field: "organizationId",
1336
+ value: organizationId,
1337
+ operator: "eq",
1338
+ connector: "AND"
1339
+ }, condition],
1340
+ update
1341
+ });
1342
+ return ctx.json({
1343
+ success: true,
1344
+ roleData: {
1345
+ ...role,
1346
+ ...update,
1347
+ permission: updateData.permission || role.permission || null
1348
+ }
1349
+ });
1350
+ });
1351
+ };
1352
+ async function checkForInvalidResources({ ac, ctx, permission }) {
1353
+ const validResources = Object.keys(ac.statements);
1354
+ const providedResources = Object.keys(permission);
1355
+ if (providedResources.some((r) => !validResources.includes(r))) {
1356
+ ctx.context.logger.error(`[Dynamic Access Control] The provided permission includes an invalid resource.`, {
1357
+ providedResources,
1358
+ validResources
1359
+ });
1360
+ throw new APIError$1("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.INVALID_RESOURCE });
1361
+ }
1362
+ }
1363
+ async function checkIfMemberHasPermission({ ctx, permissionRequired: permission, options, organizationId, member, user, action }) {
1364
+ const hasNecessaryPermissions = [];
1365
+ const permissionEntries = Object.entries(permission);
1366
+ for await (const [resource, permissions] of permissionEntries) for await (const perm of permissions) hasNecessaryPermissions.push({
1367
+ resource: { [resource]: [perm] },
1368
+ hasPermission: await hasPermission({
1369
+ options,
1370
+ organizationId,
1371
+ permissions: { [resource]: [perm] },
1372
+ useMemoryCache: true,
1373
+ role: member.role
1374
+ }, ctx)
1375
+ });
1376
+ const missingPermissions = hasNecessaryPermissions.filter((x) => x.hasPermission === false).map((x) => {
1377
+ const key = Object.keys(x.resource)[0];
1378
+ return `${key}:${x.resource[key][0]}`;
1379
+ });
1380
+ if (missingPermissions.length > 0) {
1381
+ ctx.context.logger.error(`[Dynamic Access Control] The user is missing permissions nessesary to ${action} a role with those set of permissions.\n`, {
1382
+ userId: user.id,
1383
+ organizationId,
1384
+ role: member.role,
1385
+ missingPermissions
1386
+ });
1387
+ let errorMessage;
1388
+ if (action === "create") errorMessage = ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_CREATE_A_ROLE;
1389
+ else if (action === "update") errorMessage = ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_UPDATE_A_ROLE;
1390
+ else if (action === "delete") errorMessage = ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_DELETE_A_ROLE;
1391
+ else if (action === "read") errorMessage = ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_READ_A_ROLE;
1392
+ else if (action === "list") errorMessage = ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_LIST_A_ROLE;
1393
+ else errorMessage = ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_GET_A_ROLE;
1394
+ throw new APIError$1("FORBIDDEN", {
1395
+ message: errorMessage,
1396
+ missingPermissions
1397
+ });
1398
+ }
1399
+ }
1400
+ async function checkIfRoleNameIsTakenByPreDefinedRole({ options, organizationId, role, ctx }) {
1401
+ const defaultRoles$2 = options.roles ? Object.keys(options.roles) : [
1402
+ "owner",
1403
+ "admin",
1404
+ "member"
1405
+ ];
1406
+ if (defaultRoles$2.includes(role)) {
1407
+ ctx.context.logger.error(`[Dynamic Access Control] The role name "${role}" is already taken by a pre-defined role.`, {
1408
+ role,
1409
+ organizationId,
1410
+ defaultRoles: defaultRoles$2
1411
+ });
1412
+ throw new APIError$1("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ROLE_NAME_IS_ALREADY_TAKEN });
1413
+ }
1414
+ }
1415
+ async function checkIfRoleNameIsTakenByRoleInDB({ organizationId, role, ctx }) {
1416
+ if (await ctx.context.adapter.findOne({
1417
+ model: "organizationRole",
1418
+ where: [{
1419
+ field: "organizationId",
1420
+ value: organizationId,
1421
+ operator: "eq",
1422
+ connector: "AND"
1423
+ }, {
1424
+ field: "role",
1425
+ value: role,
1426
+ operator: "eq",
1427
+ connector: "AND"
1428
+ }]
1429
+ })) {
1430
+ ctx.context.logger.error(`[Dynamic Access Control] The role name "${role}" is already taken by a role in the database.`, {
1431
+ role,
1432
+ organizationId
1433
+ });
1434
+ throw new APIError$1("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ROLE_NAME_IS_ALREADY_TAKEN });
1435
+ }
1436
+ }
1437
+
1438
+ //#endregion
1439
+ //#region src/plugins/organization/schema.ts
1440
+ const roleSchema = z.string();
1441
+ const invitationStatus = z.enum([
1442
+ "pending",
1443
+ "accepted",
1444
+ "rejected",
1445
+ "canceled"
1446
+ ]).default("pending");
1447
+ const organizationSchema = z.object({
1448
+ id: z.string().default(generateId),
1449
+ name: z.string(),
1450
+ slug: z.string(),
1451
+ logo: z.string().nullish().optional(),
1452
+ metadata: z.record(z.string(), z.unknown()).or(z.string().transform((v) => JSON.parse(v))).optional(),
1453
+ createdAt: z.date()
1454
+ });
1455
+ const memberSchema = z.object({
1456
+ id: z.string().default(generateId),
1457
+ organizationId: z.string(),
1458
+ userId: z.coerce.string(),
1459
+ role: roleSchema,
1460
+ createdAt: z.date().default(() => /* @__PURE__ */ new Date())
1461
+ });
1462
+ const invitationSchema = z.object({
1463
+ id: z.string().default(generateId),
1464
+ organizationId: z.string(),
1465
+ email: z.string(),
1466
+ role: roleSchema,
1467
+ status: invitationStatus,
1468
+ teamId: z.string().nullish(),
1469
+ inviterId: z.string(),
1470
+ expiresAt: z.date(),
1471
+ createdAt: z.date().default(() => /* @__PURE__ */ new Date())
1472
+ });
1473
+ const teamSchema = z.object({
1474
+ id: z.string().default(generateId),
1475
+ name: z.string().min(1),
1476
+ organizationId: z.string(),
1477
+ createdAt: z.date(),
1478
+ updatedAt: z.date().optional()
1479
+ });
1480
+ const teamMemberSchema = z.object({
1481
+ id: z.string().default(generateId),
1482
+ teamId: z.string(),
1483
+ userId: z.string(),
1484
+ createdAt: z.date().default(() => /* @__PURE__ */ new Date())
1485
+ });
1486
+ const organizationRoleSchema = z.object({
1487
+ id: z.string().default(generateId),
1488
+ organizationId: z.string(),
1489
+ role: z.string(),
1490
+ permission: z.record(z.string(), z.array(z.string())),
1491
+ createdAt: z.date().default(() => /* @__PURE__ */ new Date()),
1492
+ updatedAt: z.date().optional()
1493
+ });
1494
+ const defaultRoles$1 = [
1495
+ "admin",
1496
+ "member",
1497
+ "owner"
1498
+ ];
1499
+ const defaultRolesSchema = z.union([z.enum(defaultRoles$1), z.array(z.enum(defaultRoles$1))]);
1500
+
1501
+ //#endregion
1502
+ //#region src/plugins/organization/routes/crud-invites.ts
1503
+ const createInvitation = (option) => {
1504
+ const additionalFieldsSchema = toZodSchema({
1505
+ fields: option?.schema?.invitation?.additionalFields || {},
1506
+ isClientSide: true
1507
+ });
1508
+ const baseSchema = z.object({
1509
+ email: z.string().meta({ description: "The email address of the user to invite" }),
1510
+ role: z.union([z.string().meta({ description: "The role to assign to the user" }), z.array(z.string().meta({ description: "The roles to assign to the user" }))]).meta({ description: "The role(s) to assign to the user. It can be `admin`, `member`, owner. Eg: \"member\"" }),
1511
+ organizationId: z.string().meta({ description: "The organization ID to invite the user to" }).optional(),
1512
+ resend: z.boolean().meta({ description: "Resend the invitation email, if the user is already invited. Eg: true" }).optional(),
1513
+ teamId: z.union([z.string().meta({ description: "The team ID to invite the user to" }).optional(), z.array(z.string()).meta({ description: "The team IDs to invite the user to" }).optional()])
1514
+ });
1515
+ return createAuthEndpoint("/organization/invite-member", {
1516
+ method: "POST",
1517
+ use: [orgMiddleware, orgSessionMiddleware],
1518
+ body: z.object({
1519
+ ...baseSchema.shape,
1520
+ ...additionalFieldsSchema.shape
1521
+ }),
1522
+ metadata: {
1523
+ $Infer: { body: {} },
1524
+ openapi: {
1525
+ description: "Invite a user to an organization",
1526
+ responses: { "200": {
1527
+ description: "Success",
1528
+ content: { "application/json": { schema: {
1529
+ type: "object",
1530
+ properties: {
1531
+ id: { type: "string" },
1532
+ email: { type: "string" },
1533
+ role: { type: "string" },
1534
+ organizationId: { type: "string" },
1535
+ inviterId: { type: "string" },
1536
+ status: { type: "string" },
1537
+ expiresAt: { type: "string" },
1538
+ createdAt: { type: "string" }
1539
+ },
1540
+ required: [
1541
+ "id",
1542
+ "email",
1543
+ "role",
1544
+ "organizationId",
1545
+ "inviterId",
1546
+ "status",
1547
+ "expiresAt",
1548
+ "createdAt"
1549
+ ]
1550
+ } } }
1551
+ } }
1552
+ }
1553
+ }
1554
+ }, async (ctx) => {
1555
+ const session = ctx.context.session;
1556
+ const organizationId = ctx.body.organizationId || session.session.activeOrganizationId;
1557
+ if (!organizationId) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_NOT_FOUND });
1558
+ const email = ctx.body.email.toLowerCase();
1559
+ if (!z.string().email().safeParse(email).success) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.INVALID_EMAIL });
1560
+ const adapter = getOrgAdapter(ctx.context, option);
1561
+ const member = await adapter.findMemberByOrgId({
1562
+ userId: session.user.id,
1563
+ organizationId
1564
+ });
1565
+ if (!member) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.MEMBER_NOT_FOUND });
1566
+ if (!await hasPermission({
1567
+ role: member.role,
1568
+ options: ctx.context.orgOptions,
1569
+ permissions: { invitation: ["create"] },
1570
+ organizationId
1571
+ }, ctx)) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_INVITE_USERS_TO_THIS_ORGANIZATION });
1572
+ const creatorRole = ctx.context.orgOptions.creatorRole || "owner";
1573
+ const roles = parseRoles(ctx.body.role);
1574
+ if (member.role !== creatorRole && roles.split(",").includes(creatorRole)) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_INVITE_USER_WITH_THIS_ROLE });
1575
+ if (await adapter.findMemberByEmail({
1576
+ email,
1577
+ organizationId
1578
+ })) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.USER_IS_ALREADY_A_MEMBER_OF_THIS_ORGANIZATION });
1579
+ const alreadyInvited = await adapter.findPendingInvitation({
1580
+ email,
1581
+ organizationId
1582
+ });
1583
+ if (alreadyInvited.length && !ctx.body.resend) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.USER_IS_ALREADY_INVITED_TO_THIS_ORGANIZATION });
1584
+ const organization$1 = await adapter.findOrganizationById(organizationId);
1585
+ if (!organization$1) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_NOT_FOUND });
1586
+ if (alreadyInvited.length && ctx.body.resend) {
1587
+ const existingInvitation = alreadyInvited[0];
1588
+ const newExpiresAt = getDate(ctx.context.orgOptions.invitationExpiresIn || 3600 * 48, "sec");
1589
+ await ctx.context.adapter.update({
1590
+ model: "invitation",
1591
+ where: [{
1592
+ field: "id",
1593
+ value: existingInvitation.id
1594
+ }],
1595
+ update: { expiresAt: newExpiresAt }
1596
+ });
1597
+ const updatedInvitation = {
1598
+ ...existingInvitation,
1599
+ expiresAt: newExpiresAt
1600
+ };
1601
+ await ctx.context.orgOptions.sendInvitationEmail?.({
1602
+ id: updatedInvitation.id,
1603
+ role: updatedInvitation.role,
1604
+ email: updatedInvitation.email.toLowerCase(),
1605
+ organization: organization$1,
1606
+ inviter: {
1607
+ ...member,
1608
+ user: session.user
1609
+ },
1610
+ invitation: updatedInvitation
1611
+ }, ctx.request);
1612
+ return ctx.json(updatedInvitation);
1613
+ }
1614
+ if (alreadyInvited.length && ctx.context.orgOptions.cancelPendingInvitationsOnReInvite) await adapter.updateInvitation({
1615
+ invitationId: alreadyInvited[0].id,
1616
+ status: "canceled"
1617
+ });
1618
+ const invitationLimit = typeof ctx.context.orgOptions.invitationLimit === "function" ? await ctx.context.orgOptions.invitationLimit({
1619
+ user: session.user,
1620
+ organization: organization$1,
1621
+ member
1622
+ }, ctx.context) : ctx.context.orgOptions.invitationLimit ?? 100;
1623
+ if ((await adapter.findPendingInvitations({ organizationId })).length >= invitationLimit) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.INVITATION_LIMIT_REACHED });
1624
+ if (ctx.context.orgOptions.teams && ctx.context.orgOptions.teams.enabled && typeof ctx.context.orgOptions.teams.maximumMembersPerTeam !== "undefined" && "teamId" in ctx.body && ctx.body.teamId) {
1625
+ const teamIds$1 = typeof ctx.body.teamId === "string" ? [ctx.body.teamId] : ctx.body.teamId;
1626
+ for (const teamId of teamIds$1) {
1627
+ const team = await adapter.findTeamById({
1628
+ teamId,
1629
+ organizationId,
1630
+ includeTeamMembers: true
1631
+ });
1632
+ if (!team) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.TEAM_NOT_FOUND });
1633
+ const maximumMembersPerTeam = typeof ctx.context.orgOptions.teams.maximumMembersPerTeam === "function" ? await ctx.context.orgOptions.teams.maximumMembersPerTeam({
1634
+ teamId,
1635
+ session,
1636
+ organizationId
1637
+ }) : ctx.context.orgOptions.teams.maximumMembersPerTeam;
1638
+ if (team.members.length >= maximumMembersPerTeam) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.TEAM_MEMBER_LIMIT_REACHED });
1639
+ }
1640
+ }
1641
+ const teamIds = "teamId" in ctx.body ? typeof ctx.body.teamId === "string" ? [ctx.body.teamId] : ctx.body.teamId ?? [] : [];
1642
+ const { email: _, role: __, organizationId: ___, resend: ____,...additionalFields } = ctx.body;
1643
+ let invitationData = {
1644
+ role: roles,
1645
+ email,
1646
+ organizationId,
1647
+ teamIds,
1648
+ ...additionalFields ? additionalFields : {}
1649
+ };
1650
+ if (option?.organizationHooks?.beforeCreateInvitation) {
1651
+ const response = await option?.organizationHooks.beforeCreateInvitation({
1652
+ invitation: {
1653
+ ...invitationData,
1654
+ inviterId: session.user.id,
1655
+ teamId: teamIds.length > 0 ? teamIds[0] : void 0
1656
+ },
1657
+ inviter: session.user,
1658
+ organization: organization$1
1659
+ });
1660
+ if (response && typeof response === "object" && "data" in response) invitationData = {
1661
+ ...invitationData,
1662
+ ...response.data
1663
+ };
1664
+ }
1665
+ const invitation = await adapter.createInvitation({
1666
+ invitation: invitationData,
1667
+ user: session.user
1668
+ });
1669
+ await ctx.context.orgOptions.sendInvitationEmail?.({
1670
+ id: invitation.id,
1671
+ role: invitation.role,
1672
+ email: invitation.email.toLowerCase(),
1673
+ organization: organization$1,
1674
+ inviter: {
1675
+ ...member,
1676
+ user: session.user
1677
+ },
1678
+ invitation
1679
+ }, ctx.request);
1680
+ if (option?.organizationHooks?.afterCreateInvitation) await option?.organizationHooks.afterCreateInvitation({
1681
+ invitation,
1682
+ inviter: session.user,
1683
+ organization: organization$1
1684
+ });
1685
+ return ctx.json(invitation);
1686
+ });
1687
+ };
1688
+ const acceptInvitation = (options) => createAuthEndpoint("/organization/accept-invitation", {
1689
+ method: "POST",
1690
+ body: z.object({ invitationId: z.string().meta({ description: "The ID of the invitation to accept" }) }),
1691
+ use: [orgMiddleware, orgSessionMiddleware],
1692
+ metadata: { openapi: {
1693
+ description: "Accept an invitation to an organization",
1694
+ responses: { "200": {
1695
+ description: "Success",
1696
+ content: { "application/json": { schema: {
1697
+ type: "object",
1698
+ properties: {
1699
+ invitation: { type: "object" },
1700
+ member: { type: "object" }
1701
+ }
1702
+ } } }
1703
+ } }
1704
+ } }
1705
+ }, async (ctx) => {
1706
+ const session = ctx.context.session;
1707
+ const adapter = getOrgAdapter(ctx.context, options);
1708
+ const invitation = await adapter.findInvitationById(ctx.body.invitationId);
1709
+ if (!invitation || invitation.expiresAt < /* @__PURE__ */ new Date() || invitation.status !== "pending") throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.INVITATION_NOT_FOUND });
1710
+ if (invitation.email.toLowerCase() !== session.user.email.toLowerCase()) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_THE_RECIPIENT_OF_THE_INVITATION });
1711
+ if (ctx.context.orgOptions.requireEmailVerificationOnInvitation && !session.user.emailVerified) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.EMAIL_VERIFICATION_REQUIRED_BEFORE_ACCEPTING_OR_REJECTING_INVITATION });
1712
+ const membershipLimit = ctx.context.orgOptions?.membershipLimit || 100;
1713
+ if (await adapter.countMembers({ organizationId: invitation.organizationId }) >= membershipLimit) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_MEMBERSHIP_LIMIT_REACHED });
1714
+ const organization$1 = await adapter.findOrganizationById(invitation.organizationId);
1715
+ if (!organization$1) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_NOT_FOUND });
1716
+ if (options?.organizationHooks?.beforeAcceptInvitation) await options?.organizationHooks.beforeAcceptInvitation({
1717
+ invitation,
1718
+ user: session.user,
1719
+ organization: organization$1
1720
+ });
1721
+ const acceptedI = await adapter.updateInvitation({
1722
+ invitationId: ctx.body.invitationId,
1723
+ status: "accepted"
1724
+ });
1725
+ if (!acceptedI) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.FAILED_TO_RETRIEVE_INVITATION });
1726
+ if (ctx.context.orgOptions.teams && ctx.context.orgOptions.teams.enabled && "teamId" in acceptedI && acceptedI.teamId) {
1727
+ const teamIds = acceptedI.teamId.split(",");
1728
+ const onlyOne = teamIds.length === 1;
1729
+ for (const teamId of teamIds) {
1730
+ await adapter.findOrCreateTeamMember({
1731
+ teamId,
1732
+ userId: session.user.id
1733
+ });
1734
+ if (typeof ctx.context.orgOptions.teams.maximumMembersPerTeam !== "undefined") {
1735
+ if (await adapter.countTeamMembers({ teamId }) >= (typeof ctx.context.orgOptions.teams.maximumMembersPerTeam === "function" ? await ctx.context.orgOptions.teams.maximumMembersPerTeam({
1736
+ teamId,
1737
+ session,
1738
+ organizationId: invitation.organizationId
1739
+ }) : ctx.context.orgOptions.teams.maximumMembersPerTeam)) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.TEAM_MEMBER_LIMIT_REACHED });
1740
+ }
1741
+ }
1742
+ if (onlyOne) {
1743
+ const teamId = teamIds[0];
1744
+ await setSessionCookie(ctx, {
1745
+ session: await adapter.setActiveTeam(session.session.token, teamId, ctx),
1746
+ user: session.user
1747
+ });
1748
+ }
1749
+ }
1750
+ const member = await adapter.createMember({
1751
+ organizationId: invitation.organizationId,
1752
+ userId: session.user.id,
1753
+ role: invitation.role,
1754
+ createdAt: /* @__PURE__ */ new Date()
1755
+ });
1756
+ await adapter.setActiveOrganization(session.session.token, invitation.organizationId, ctx);
1757
+ if (!acceptedI) return ctx.json(null, {
1758
+ status: 400,
1759
+ body: { message: ORGANIZATION_ERROR_CODES.INVITATION_NOT_FOUND }
1760
+ });
1761
+ if (options?.organizationHooks?.afterAcceptInvitation) await options?.organizationHooks.afterAcceptInvitation({
1762
+ invitation: acceptedI,
1763
+ member,
1764
+ user: session.user,
1765
+ organization: organization$1
1766
+ });
1767
+ return ctx.json({
1768
+ invitation: acceptedI,
1769
+ member
1770
+ });
1771
+ });
1772
+ const rejectInvitation = (options) => createAuthEndpoint("/organization/reject-invitation", {
1773
+ method: "POST",
1774
+ body: z.object({ invitationId: z.string().meta({ description: "The ID of the invitation to reject" }) }),
1775
+ use: [orgMiddleware, orgSessionMiddleware],
1776
+ metadata: { openapi: {
1777
+ description: "Reject an invitation to an organization",
1778
+ responses: { "200": {
1779
+ description: "Success",
1780
+ content: { "application/json": { schema: {
1781
+ type: "object",
1782
+ properties: {
1783
+ invitation: { type: "object" },
1784
+ member: { type: "null" }
1785
+ }
1786
+ } } }
1787
+ } }
1788
+ } }
1789
+ }, async (ctx) => {
1790
+ const session = ctx.context.session;
1791
+ const adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);
1792
+ const invitation = await adapter.findInvitationById(ctx.body.invitationId);
1793
+ if (!invitation || invitation.expiresAt < /* @__PURE__ */ new Date() || invitation.status !== "pending") throw new APIError("BAD_REQUEST", { message: "Invitation not found!" });
1794
+ if (invitation.email.toLowerCase() !== session.user.email.toLowerCase()) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_THE_RECIPIENT_OF_THE_INVITATION });
1795
+ if (ctx.context.orgOptions.requireEmailVerificationOnInvitation && !session.user.emailVerified) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.EMAIL_VERIFICATION_REQUIRED_BEFORE_ACCEPTING_OR_REJECTING_INVITATION });
1796
+ const organization$1 = await adapter.findOrganizationById(invitation.organizationId);
1797
+ if (!organization$1) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_NOT_FOUND });
1798
+ if (options?.organizationHooks?.beforeRejectInvitation) await options?.organizationHooks.beforeRejectInvitation({
1799
+ invitation,
1800
+ user: session.user,
1801
+ organization: organization$1
1802
+ });
1803
+ const rejectedI = await adapter.updateInvitation({
1804
+ invitationId: ctx.body.invitationId,
1805
+ status: "rejected"
1806
+ });
1807
+ if (options?.organizationHooks?.afterRejectInvitation) await options?.organizationHooks.afterRejectInvitation({
1808
+ invitation: rejectedI || invitation,
1809
+ user: session.user,
1810
+ organization: organization$1
1811
+ });
1812
+ return ctx.json({
1813
+ invitation: rejectedI,
1814
+ member: null
1815
+ });
1816
+ });
1817
+ const cancelInvitation = (options) => createAuthEndpoint("/organization/cancel-invitation", {
1818
+ method: "POST",
1819
+ body: z.object({ invitationId: z.string().meta({ description: "The ID of the invitation to cancel" }) }),
1820
+ use: [orgMiddleware, orgSessionMiddleware],
1821
+ openapi: {
1822
+ description: "Cancel an invitation to an organization",
1823
+ responses: { "200": {
1824
+ description: "Success",
1825
+ content: { "application/json": { schema: {
1826
+ type: "object",
1827
+ properties: { invitation: { type: "object" } }
1828
+ } } }
1829
+ } }
1830
+ }
1831
+ }, async (ctx) => {
1832
+ const session = ctx.context.session;
1833
+ const adapter = getOrgAdapter(ctx.context, options);
1834
+ const invitation = await adapter.findInvitationById(ctx.body.invitationId);
1835
+ if (!invitation) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.INVITATION_NOT_FOUND });
1836
+ const member = await adapter.findMemberByOrgId({
1837
+ userId: session.user.id,
1838
+ organizationId: invitation.organizationId
1839
+ });
1840
+ if (!member) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.MEMBER_NOT_FOUND });
1841
+ if (!await hasPermission({
1842
+ role: member.role,
1843
+ options: ctx.context.orgOptions,
1844
+ permissions: { invitation: ["cancel"] },
1845
+ organizationId: invitation.organizationId
1846
+ }, ctx)) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_CANCEL_THIS_INVITATION });
1847
+ const organization$1 = await adapter.findOrganizationById(invitation.organizationId);
1848
+ if (!organization$1) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_NOT_FOUND });
1849
+ if (options?.organizationHooks?.beforeCancelInvitation) await options?.organizationHooks.beforeCancelInvitation({
1850
+ invitation,
1851
+ cancelledBy: session.user,
1852
+ organization: organization$1
1853
+ });
1854
+ const canceledI = await adapter.updateInvitation({
1855
+ invitationId: ctx.body.invitationId,
1856
+ status: "canceled"
1857
+ });
1858
+ if (options?.organizationHooks?.afterCancelInvitation) await options?.organizationHooks.afterCancelInvitation({
1859
+ invitation: canceledI || invitation,
1860
+ cancelledBy: session.user,
1861
+ organization: organization$1
1862
+ });
1863
+ return ctx.json(canceledI);
1864
+ });
1865
+ const getInvitation = (options) => createAuthEndpoint("/organization/get-invitation", {
1866
+ method: "GET",
1867
+ use: [orgMiddleware],
1868
+ requireHeaders: true,
1869
+ query: z.object({ id: z.string().meta({ description: "The ID of the invitation to get" }) }),
1870
+ metadata: { openapi: {
1871
+ description: "Get an invitation by ID",
1872
+ responses: { "200": {
1873
+ description: "Success",
1874
+ content: { "application/json": { schema: {
1875
+ type: "object",
1876
+ properties: {
1877
+ id: { type: "string" },
1878
+ email: { type: "string" },
1879
+ role: { type: "string" },
1880
+ organizationId: { type: "string" },
1881
+ inviterId: { type: "string" },
1882
+ status: { type: "string" },
1883
+ expiresAt: { type: "string" },
1884
+ organizationName: { type: "string" },
1885
+ organizationSlug: { type: "string" },
1886
+ inviterEmail: { type: "string" }
1887
+ },
1888
+ required: [
1889
+ "id",
1890
+ "email",
1891
+ "role",
1892
+ "organizationId",
1893
+ "inviterId",
1894
+ "status",
1895
+ "expiresAt",
1896
+ "organizationName",
1897
+ "organizationSlug",
1898
+ "inviterEmail"
1899
+ ]
1900
+ } } }
1901
+ } }
1902
+ } }
1903
+ }, async (ctx) => {
1904
+ const session = await getSessionFromCtx(ctx);
1905
+ if (!session) throw new APIError("UNAUTHORIZED", { message: "Not authenticated" });
1906
+ const adapter = getOrgAdapter(ctx.context, options);
1907
+ const invitation = await adapter.findInvitationById(ctx.query.id);
1908
+ if (!invitation || invitation.status !== "pending" || invitation.expiresAt < /* @__PURE__ */ new Date()) throw new APIError("BAD_REQUEST", { message: "Invitation not found!" });
1909
+ if (invitation.email.toLowerCase() !== session.user.email.toLowerCase()) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_THE_RECIPIENT_OF_THE_INVITATION });
1910
+ const organization$1 = await adapter.findOrganizationById(invitation.organizationId);
1911
+ if (!organization$1) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_NOT_FOUND });
1912
+ const member = await adapter.findMemberByOrgId({
1913
+ userId: invitation.inviterId,
1914
+ organizationId: invitation.organizationId
1915
+ });
1916
+ if (!member) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.INVITER_IS_NO_LONGER_A_MEMBER_OF_THE_ORGANIZATION });
1917
+ return ctx.json({
1918
+ ...invitation,
1919
+ organizationName: organization$1.name,
1920
+ organizationSlug: organization$1.slug,
1921
+ inviterEmail: member.user.email
1922
+ });
1923
+ });
1924
+ const listInvitations = (options) => createAuthEndpoint("/organization/list-invitations", {
1925
+ method: "GET",
1926
+ use: [orgMiddleware, orgSessionMiddleware],
1927
+ query: z.object({ organizationId: z.string().meta({ description: "The ID of the organization to list invitations for" }).optional() }).optional()
1928
+ }, async (ctx) => {
1929
+ const session = await getSessionFromCtx(ctx);
1930
+ if (!session) throw new APIError("UNAUTHORIZED", { message: "Not authenticated" });
1931
+ const orgId = ctx.query?.organizationId || session.session.activeOrganizationId;
1932
+ if (!orgId) throw new APIError("BAD_REQUEST", { message: "Organization ID is required" });
1933
+ const adapter = getOrgAdapter(ctx.context, options);
1934
+ if (!await adapter.findMemberByOrgId({
1935
+ userId: session.user.id,
1936
+ organizationId: orgId
1937
+ })) throw new APIError("FORBIDDEN", { message: "You are not a member of this organization" });
1938
+ const invitations = await adapter.listInvitations({ organizationId: orgId });
1939
+ return ctx.json(invitations);
1940
+ });
1941
+ /**
1942
+ * List all invitations a user has received
1943
+ */
1944
+ const listUserInvitations = (options) => createAuthEndpoint("/organization/list-user-invitations", {
1945
+ method: "GET",
1946
+ use: [orgMiddleware],
1947
+ query: z.object({ email: z.string().meta({ description: "The email of the user to list invitations for. This only works for server side API calls." }).optional() }).optional()
1948
+ }, async (ctx) => {
1949
+ const session = await getSessionFromCtx(ctx);
1950
+ if (ctx.request && ctx.query?.email) throw new APIError("BAD_REQUEST", { message: "User email cannot be passed for client side API calls." });
1951
+ const userEmail = session?.user.email || ctx.query?.email;
1952
+ if (!userEmail) throw new APIError("BAD_REQUEST", { message: "Missing session headers, or email query parameter." });
1953
+ const invitations = await getOrgAdapter(ctx.context, options).listUserInvitations(userEmail);
1954
+ return ctx.json(invitations);
1955
+ });
1956
+
1957
+ //#endregion
1958
+ //#region src/plugins/organization/routes/crud-members.ts
1959
+ const addMember = (option) => {
1960
+ const additionalFieldsSchema = toZodSchema({
1961
+ fields: option?.schema?.member?.additionalFields || {},
1962
+ isClientSide: true
1963
+ });
1964
+ const baseSchema = z.object({
1965
+ userId: z.coerce.string().meta({ description: "The user Id which represents the user to be added as a member. If `null` is provided, then it's expected to provide session headers. Eg: \"user-id\"" }),
1966
+ role: z.union([z.string(), z.array(z.string())]).meta({ description: "The role(s) to assign to the new member. Eg: [\"admin\", \"sale\"]" }),
1967
+ organizationId: z.string().meta({ description: "An optional organization ID to pass. If not provided, will default to the user's active organization. Eg: \"org-id\"" }).optional(),
1968
+ teamId: z.string().meta({ description: "An optional team ID to add the member to. Eg: \"team-id\"" }).optional()
1969
+ });
1970
+ return createAuthEndpoint("/organization/add-member", {
1971
+ method: "POST",
1972
+ body: z.object({
1973
+ ...baseSchema.shape,
1974
+ ...additionalFieldsSchema.shape
1975
+ }),
1976
+ use: [orgMiddleware],
1977
+ metadata: {
1978
+ SERVER_ONLY: true,
1979
+ $Infer: { body: {} }
1980
+ }
1981
+ }, async (ctx) => {
1982
+ const session = ctx.body.userId ? await getSessionFromCtx(ctx).catch((e) => null) : null;
1983
+ const orgId = ctx.body.organizationId || session?.session.activeOrganizationId;
1984
+ if (!orgId) return ctx.json(null, {
1985
+ status: 400,
1986
+ body: { message: ORGANIZATION_ERROR_CODES.NO_ACTIVE_ORGANIZATION }
1987
+ });
1988
+ const teamId = "teamId" in ctx.body ? ctx.body.teamId : void 0;
1989
+ if (teamId && !ctx.context.orgOptions.teams?.enabled) {
1990
+ ctx.context.logger.error("Teams are not enabled");
1991
+ throw new APIError("BAD_REQUEST", { message: "Teams are not enabled" });
1992
+ }
1993
+ const adapter = getOrgAdapter(ctx.context, option);
1994
+ const user = await ctx.context.internalAdapter.findUserById(ctx.body.userId);
1995
+ if (!user) throw new APIError("BAD_REQUEST", { message: BASE_ERROR_CODES.USER_NOT_FOUND });
1996
+ if (await adapter.findMemberByEmail({
1997
+ email: user.email,
1998
+ organizationId: orgId
1999
+ })) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.USER_IS_ALREADY_A_MEMBER_OF_THIS_ORGANIZATION });
2000
+ if (teamId) {
2001
+ const team = await adapter.findTeamById({
2002
+ teamId,
2003
+ organizationId: orgId
2004
+ });
2005
+ if (!team || team.organizationId !== orgId) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.TEAM_NOT_FOUND });
2006
+ }
2007
+ const membershipLimit = ctx.context.orgOptions?.membershipLimit || 100;
2008
+ if (await adapter.countMembers({ organizationId: orgId }) >= membershipLimit) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_MEMBERSHIP_LIMIT_REACHED });
2009
+ const { role: _, userId: __, organizationId: ___,...additionalFields } = ctx.body;
2010
+ const organization$1 = await adapter.findOrganizationById(orgId);
2011
+ if (!organization$1) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_NOT_FOUND });
2012
+ let memberData = {
2013
+ organizationId: orgId,
2014
+ userId: user.id,
2015
+ role: parseRoles(ctx.body.role),
2016
+ createdAt: /* @__PURE__ */ new Date(),
2017
+ ...additionalFields ? additionalFields : {}
2018
+ };
2019
+ if (option?.organizationHooks?.beforeAddMember) {
2020
+ const response = await option?.organizationHooks.beforeAddMember({
2021
+ member: {
2022
+ userId: user.id,
2023
+ organizationId: orgId,
2024
+ role: parseRoles(ctx.body.role),
2025
+ ...additionalFields
2026
+ },
2027
+ user,
2028
+ organization: organization$1
2029
+ });
2030
+ if (response && typeof response === "object" && "data" in response) memberData = {
2031
+ ...memberData,
2032
+ ...response.data
2033
+ };
2034
+ }
2035
+ const createdMember = await adapter.createMember(memberData);
2036
+ if (teamId) await adapter.findOrCreateTeamMember({
2037
+ userId: user.id,
2038
+ teamId
2039
+ });
2040
+ if (option?.organizationHooks?.afterAddMember) await option?.organizationHooks.afterAddMember({
2041
+ member: createdMember,
2042
+ user,
2043
+ organization: organization$1
2044
+ });
2045
+ return ctx.json(createdMember);
2046
+ });
2047
+ };
2048
+ const removeMember = (options) => createAuthEndpoint("/organization/remove-member", {
2049
+ method: "POST",
2050
+ body: z.object({
2051
+ memberIdOrEmail: z.string().meta({ description: "The ID or email of the member to remove" }),
2052
+ organizationId: z.string().meta({ description: "The ID of the organization to remove the member from. If not provided, the active organization will be used. Eg: \"org-id\"" }).optional()
2053
+ }),
2054
+ use: [orgMiddleware, orgSessionMiddleware],
2055
+ metadata: { openapi: {
2056
+ description: "Remove a member from an organization",
2057
+ responses: { "200": {
2058
+ description: "Success",
2059
+ content: { "application/json": { schema: {
2060
+ type: "object",
2061
+ properties: { member: {
2062
+ type: "object",
2063
+ properties: {
2064
+ id: { type: "string" },
2065
+ userId: { type: "string" },
2066
+ organizationId: { type: "string" },
2067
+ role: { type: "string" }
2068
+ },
2069
+ required: [
2070
+ "id",
2071
+ "userId",
2072
+ "organizationId",
2073
+ "role"
2074
+ ]
2075
+ } },
2076
+ required: ["member"]
2077
+ } } }
2078
+ } }
2079
+ } }
2080
+ }, async (ctx) => {
2081
+ const session = ctx.context.session;
2082
+ const organizationId = ctx.body.organizationId || session.session.activeOrganizationId;
2083
+ if (!organizationId) return ctx.json(null, {
2084
+ status: 400,
2085
+ body: { message: ORGANIZATION_ERROR_CODES.NO_ACTIVE_ORGANIZATION }
2086
+ });
2087
+ const adapter = getOrgAdapter(ctx.context, options);
2088
+ const member = await adapter.findMemberByOrgId({
2089
+ userId: session.user.id,
2090
+ organizationId
2091
+ });
2092
+ if (!member) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.MEMBER_NOT_FOUND });
2093
+ let toBeRemovedMember = null;
2094
+ if (ctx.body.memberIdOrEmail.includes("@")) toBeRemovedMember = await adapter.findMemberByEmail({
2095
+ email: ctx.body.memberIdOrEmail,
2096
+ organizationId
2097
+ });
2098
+ else toBeRemovedMember = await adapter.findMemberById(ctx.body.memberIdOrEmail);
2099
+ if (!toBeRemovedMember) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.MEMBER_NOT_FOUND });
2100
+ const roles = toBeRemovedMember.role.split(",");
2101
+ const creatorRole = ctx.context.orgOptions?.creatorRole || "owner";
2102
+ if (roles.includes(creatorRole)) {
2103
+ if (member.role !== creatorRole) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.YOU_CANNOT_LEAVE_THE_ORGANIZATION_AS_THE_ONLY_OWNER });
2104
+ const { members } = await adapter.listMembers({ organizationId });
2105
+ if (members.filter((member$1) => {
2106
+ return member$1.role.split(",").includes(creatorRole);
2107
+ }).length <= 1) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.YOU_CANNOT_LEAVE_THE_ORGANIZATION_AS_THE_ONLY_OWNER });
2108
+ }
2109
+ if (!await hasPermission({
2110
+ role: member.role,
2111
+ options: ctx.context.orgOptions,
2112
+ permissions: { member: ["delete"] },
2113
+ organizationId
2114
+ }, ctx)) throw new APIError("UNAUTHORIZED", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_MEMBER });
2115
+ if (toBeRemovedMember?.organizationId !== organizationId) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.MEMBER_NOT_FOUND });
2116
+ const organization$1 = await adapter.findOrganizationById(organizationId);
2117
+ if (!organization$1) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_NOT_FOUND });
2118
+ const userBeingRemoved = await ctx.context.internalAdapter.findUserById(toBeRemovedMember.userId);
2119
+ if (!userBeingRemoved) throw new APIError("BAD_REQUEST", { message: "User not found" });
2120
+ if (options?.organizationHooks?.beforeRemoveMember) await options?.organizationHooks.beforeRemoveMember({
2121
+ member: toBeRemovedMember,
2122
+ user: userBeingRemoved,
2123
+ organization: organization$1
2124
+ });
2125
+ await adapter.deleteMember({
2126
+ memberId: toBeRemovedMember.id,
2127
+ organizationId,
2128
+ userId: toBeRemovedMember.userId
2129
+ });
2130
+ if (session.user.id === toBeRemovedMember.userId && session.session.activeOrganizationId === toBeRemovedMember.organizationId) await adapter.setActiveOrganization(session.session.token, null, ctx);
2131
+ if (options?.organizationHooks?.afterRemoveMember) await options?.organizationHooks.afterRemoveMember({
2132
+ member: toBeRemovedMember,
2133
+ user: userBeingRemoved,
2134
+ organization: organization$1
2135
+ });
2136
+ return ctx.json({ member: toBeRemovedMember });
2137
+ });
2138
+ const updateMemberRole = (option) => createAuthEndpoint("/organization/update-member-role", {
2139
+ method: "POST",
2140
+ body: z.object({
2141
+ role: z.union([z.string(), z.array(z.string())]).meta({ description: "The new role to be applied. This can be a string or array of strings representing the roles. Eg: [\"admin\", \"sale\"]" }),
2142
+ memberId: z.string().meta({ description: "The member id to apply the role update to. Eg: \"member-id\"" }),
2143
+ organizationId: z.string().meta({ description: "An optional organization ID which the member is a part of to apply the role update. If not provided, you must provide session headers to get the active organization. Eg: \"organization-id\"" }).optional()
2144
+ }),
2145
+ use: [orgMiddleware, orgSessionMiddleware],
2146
+ metadata: {
2147
+ $Infer: { body: {} },
2148
+ openapi: {
2149
+ description: "Update the role of a member in an organization",
2150
+ responses: { "200": {
2151
+ description: "Success",
2152
+ content: { "application/json": { schema: {
2153
+ type: "object",
2154
+ properties: { member: {
2155
+ type: "object",
2156
+ properties: {
2157
+ id: { type: "string" },
2158
+ userId: { type: "string" },
2159
+ organizationId: { type: "string" },
2160
+ role: { type: "string" }
2161
+ },
2162
+ required: [
2163
+ "id",
2164
+ "userId",
2165
+ "organizationId",
2166
+ "role"
2167
+ ]
2168
+ } },
2169
+ required: ["member"]
2170
+ } } }
2171
+ } }
2172
+ }
2173
+ }
2174
+ }, async (ctx) => {
2175
+ const session = ctx.context.session;
2176
+ if (!ctx.body.role) throw new APIError("BAD_REQUEST");
2177
+ const organizationId = ctx.body.organizationId || session.session.activeOrganizationId;
2178
+ if (!organizationId) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.NO_ACTIVE_ORGANIZATION });
2179
+ const adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);
2180
+ const roleToSet = Array.isArray(ctx.body.role) ? ctx.body.role : ctx.body.role ? [ctx.body.role] : [];
2181
+ const member = await adapter.findMemberByOrgId({
2182
+ userId: session.user.id,
2183
+ organizationId
2184
+ });
2185
+ if (!member) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.MEMBER_NOT_FOUND });
2186
+ const toBeUpdatedMember = member.id !== ctx.body.memberId ? await adapter.findMemberById(ctx.body.memberId) : member;
2187
+ if (!toBeUpdatedMember) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.MEMBER_NOT_FOUND });
2188
+ if (!(toBeUpdatedMember.organizationId === organizationId)) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_MEMBER });
2189
+ const creatorRole = ctx.context.orgOptions?.creatorRole || "owner";
2190
+ const updatingMemberRoles = member.role.split(",");
2191
+ const isUpdatingCreator = toBeUpdatedMember.role.split(",").includes(creatorRole);
2192
+ const updaterIsCreator = updatingMemberRoles.includes(creatorRole);
2193
+ const isSettingCreatorRole = roleToSet.includes(creatorRole);
2194
+ const memberIsUpdatingThemselves = member.id === toBeUpdatedMember.id;
2195
+ if (isUpdatingCreator && !updaterIsCreator || isSettingCreatorRole && !updaterIsCreator) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_MEMBER });
2196
+ if (updaterIsCreator && memberIsUpdatingThemselves) {
2197
+ if ((await ctx.context.adapter.findMany({
2198
+ model: "member",
2199
+ where: [{
2200
+ field: "organizationId",
2201
+ value: organizationId
2202
+ }]
2203
+ })).filter((member$1) => {
2204
+ return member$1.role.split(",").includes(creatorRole);
2205
+ }).length <= 1 && !isSettingCreatorRole) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.YOU_CANNOT_LEAVE_THE_ORGANIZATION_WITHOUT_AN_OWNER });
2206
+ }
2207
+ if (!await hasPermission({
2208
+ role: member.role,
2209
+ options: ctx.context.orgOptions,
2210
+ permissions: { member: ["update"] },
2211
+ allowCreatorAllPermissions: true,
2212
+ organizationId
2213
+ }, ctx)) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_MEMBER });
2214
+ const organization$1 = await adapter.findOrganizationById(organizationId);
2215
+ if (!organization$1) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_NOT_FOUND });
2216
+ const userBeingUpdated = await ctx.context.internalAdapter.findUserById(toBeUpdatedMember.userId);
2217
+ if (!userBeingUpdated) throw new APIError("BAD_REQUEST", { message: "User not found" });
2218
+ const previousRole = toBeUpdatedMember.role;
2219
+ const newRole = parseRoles(ctx.body.role);
2220
+ if (option?.organizationHooks?.beforeUpdateMemberRole) {
2221
+ const response = await option?.organizationHooks.beforeUpdateMemberRole({
2222
+ member: toBeUpdatedMember,
2223
+ newRole,
2224
+ user: userBeingUpdated,
2225
+ organization: organization$1
2226
+ });
2227
+ if (response && typeof response === "object" && "data" in response) {
2228
+ const updatedMember$1 = await adapter.updateMember(ctx.body.memberId, response.data.role || newRole);
2229
+ if (!updatedMember$1) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.MEMBER_NOT_FOUND });
2230
+ if (option?.organizationHooks?.afterUpdateMemberRole) await option?.organizationHooks.afterUpdateMemberRole({
2231
+ member: updatedMember$1,
2232
+ previousRole,
2233
+ user: userBeingUpdated,
2234
+ organization: organization$1
2235
+ });
2236
+ return ctx.json(updatedMember$1);
2237
+ }
2238
+ }
2239
+ const updatedMember = await adapter.updateMember(ctx.body.memberId, newRole);
2240
+ if (!updatedMember) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.MEMBER_NOT_FOUND });
2241
+ if (option?.organizationHooks?.afterUpdateMemberRole) await option?.organizationHooks.afterUpdateMemberRole({
2242
+ member: updatedMember,
2243
+ previousRole,
2244
+ user: userBeingUpdated,
2245
+ organization: organization$1
2246
+ });
2247
+ return ctx.json(updatedMember);
2248
+ });
2249
+ const getActiveMember = (options) => createAuthEndpoint("/organization/get-active-member", {
2250
+ method: "GET",
2251
+ use: [orgMiddleware, orgSessionMiddleware],
2252
+ requireHeaders: true,
2253
+ metadata: { openapi: {
2254
+ description: "Get the member details of the active organization",
2255
+ responses: { "200": {
2256
+ description: "Success",
2257
+ content: { "application/json": { schema: {
2258
+ type: "object",
2259
+ properties: {
2260
+ id: { type: "string" },
2261
+ userId: { type: "string" },
2262
+ organizationId: { type: "string" },
2263
+ role: { type: "string" }
2264
+ },
2265
+ required: [
2266
+ "id",
2267
+ "userId",
2268
+ "organizationId",
2269
+ "role"
2270
+ ]
2271
+ } } }
2272
+ } }
2273
+ } }
2274
+ }, async (ctx) => {
2275
+ const session = ctx.context.session;
2276
+ const organizationId = session.session.activeOrganizationId;
2277
+ if (!organizationId) return ctx.json(null, {
2278
+ status: 400,
2279
+ body: { message: ORGANIZATION_ERROR_CODES.NO_ACTIVE_ORGANIZATION }
2280
+ });
2281
+ const member = await getOrgAdapter(ctx.context, options).findMemberByOrgId({
2282
+ userId: session.user.id,
2283
+ organizationId
2284
+ });
2285
+ if (!member) return ctx.json(null, {
2286
+ status: 400,
2287
+ body: { message: ORGANIZATION_ERROR_CODES.MEMBER_NOT_FOUND }
2288
+ });
2289
+ return ctx.json(member);
2290
+ });
2291
+ const leaveOrganization = (options) => createAuthEndpoint("/organization/leave", {
2292
+ method: "POST",
2293
+ body: z.object({ organizationId: z.string().meta({ description: "The organization Id for the member to leave. Eg: \"organization-id\"" }) }),
2294
+ requireHeaders: true,
2295
+ use: [sessionMiddleware, orgMiddleware]
2296
+ }, async (ctx) => {
2297
+ const session = ctx.context.session;
2298
+ const adapter = getOrgAdapter(ctx.context, options);
2299
+ const member = await adapter.findMemberByOrgId({
2300
+ userId: session.user.id,
2301
+ organizationId: ctx.body.organizationId
2302
+ });
2303
+ if (!member) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.MEMBER_NOT_FOUND });
2304
+ const creatorRole = ctx.context.orgOptions?.creatorRole || "owner";
2305
+ if (member.role.split(",").includes(creatorRole)) {
2306
+ if ((await ctx.context.adapter.findMany({
2307
+ model: "member",
2308
+ where: [{
2309
+ field: "organizationId",
2310
+ value: ctx.body.organizationId
2311
+ }]
2312
+ })).filter((member$1) => member$1.role.split(",").includes(creatorRole)).length <= 1) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.YOU_CANNOT_LEAVE_THE_ORGANIZATION_AS_THE_ONLY_OWNER });
2313
+ }
2314
+ await adapter.deleteMember({
2315
+ memberId: member.id,
2316
+ organizationId: ctx.body.organizationId,
2317
+ userId: session.user.id
2318
+ });
2319
+ if (session.session.activeOrganizationId === ctx.body.organizationId) await adapter.setActiveOrganization(session.session.token, null, ctx);
2320
+ return ctx.json(member);
2321
+ });
2322
+ const listMembers = (options) => createAuthEndpoint("/organization/list-members", {
2323
+ method: "GET",
2324
+ query: z.object({
2325
+ limit: z.string().meta({ description: "The number of users to return" }).or(z.number()).optional(),
2326
+ offset: z.string().meta({ description: "The offset to start from" }).or(z.number()).optional(),
2327
+ sortBy: z.string().meta({ description: "The field to sort by" }).optional(),
2328
+ sortDirection: z.enum(["asc", "desc"]).meta({ description: "The direction to sort by" }).optional(),
2329
+ filterField: z.string().meta({ description: "The field to filter by" }).optional(),
2330
+ filterValue: z.string().meta({ description: "The value to filter by" }).or(z.number()).or(z.boolean()).optional(),
2331
+ filterOperator: z.enum([
2332
+ "eq",
2333
+ "ne",
2334
+ "lt",
2335
+ "lte",
2336
+ "gt",
2337
+ "gte",
2338
+ "contains"
2339
+ ]).meta({ description: "The operator to use for the filter" }).optional(),
2340
+ organizationId: z.string().meta({ description: "The organization ID to list members for. If not provided, will default to the user's active organization. Eg: \"organization-id\"" }).optional()
2341
+ }).optional(),
2342
+ use: [orgMiddleware, orgSessionMiddleware]
2343
+ }, async (ctx) => {
2344
+ const session = ctx.context.session;
2345
+ const organizationId = ctx.query?.organizationId || session.session.activeOrganizationId;
2346
+ if (!organizationId) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.NO_ACTIVE_ORGANIZATION });
2347
+ const adapter = getOrgAdapter(ctx.context, options);
2348
+ if (!await adapter.findMemberByOrgId({
2349
+ userId: session.user.id,
2350
+ organizationId
2351
+ })) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_A_MEMBER_OF_THIS_ORGANIZATION });
2352
+ const { members, total } = await adapter.listMembers({
2353
+ organizationId,
2354
+ limit: ctx.query?.limit ? Number(ctx.query.limit) : void 0,
2355
+ offset: ctx.query?.offset ? Number(ctx.query.offset) : void 0,
2356
+ sortBy: ctx.query?.sortBy,
2357
+ sortOrder: ctx.query?.sortDirection,
2358
+ filter: ctx.query?.filterField ? {
2359
+ field: ctx.query?.filterField,
2360
+ operator: ctx.query.filterOperator,
2361
+ value: ctx.query.filterValue
2362
+ } : void 0
2363
+ });
2364
+ return ctx.json({
2365
+ members,
2366
+ total
2367
+ });
2368
+ });
2369
+ const getActiveMemberRole = (options) => createAuthEndpoint("/organization/get-active-member-role", {
2370
+ method: "GET",
2371
+ query: z.object({
2372
+ userId: z.string().meta({ description: "The user ID to get the role for. If not provided, will default to the current user's" }).optional(),
2373
+ organizationId: z.string().meta({ description: "The organization ID to list members for. If not provided, will default to the user's active organization. Eg: \"organization-id\"" }).optional()
2374
+ }).optional(),
2375
+ use: [orgMiddleware, orgSessionMiddleware]
2376
+ }, async (ctx) => {
2377
+ const session = ctx.context.session;
2378
+ const organizationId = ctx.query?.organizationId || session.session.activeOrganizationId;
2379
+ if (!organizationId) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.NO_ACTIVE_ORGANIZATION });
2380
+ const userId = ctx.query?.userId || session.user.id;
2381
+ const member = await getOrgAdapter(ctx.context, options).findMemberByOrgId({
2382
+ userId,
2383
+ organizationId
2384
+ });
2385
+ if (!member) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_A_MEMBER_OF_THIS_ORGANIZATION });
2386
+ return ctx.json({ role: member?.role });
2387
+ });
2388
+
2389
+ //#endregion
2390
+ //#region src/plugins/organization/routes/crud-org.ts
2391
+ const createOrganization = (options) => {
2392
+ const additionalFieldsSchema = toZodSchema({
2393
+ fields: options?.schema?.organization?.additionalFields || {},
2394
+ isClientSide: true
2395
+ });
2396
+ const baseSchema = z.object({
2397
+ name: z.string().min(1).meta({ description: "The name of the organization" }),
2398
+ slug: z.string().min(1).meta({ description: "The slug of the organization" }),
2399
+ userId: z.coerce.string().meta({ description: "The user id of the organization creator. If not provided, the current user will be used. Should only be used by admins or when called by the server. server-only. Eg: \"user-id\"" }).optional(),
2400
+ logo: z.string().meta({ description: "The logo of the organization" }).optional(),
2401
+ metadata: z.record(z.string(), z.any()).meta({ description: "The metadata of the organization" }).optional(),
2402
+ keepCurrentActiveOrganization: z.boolean().meta({ description: "Whether to keep the current active organization active after creating a new one. Eg: true" }).optional()
2403
+ });
2404
+ return createAuthEndpoint("/organization/create", {
2405
+ method: "POST",
2406
+ body: z.object({
2407
+ ...baseSchema.shape,
2408
+ ...additionalFieldsSchema.shape
2409
+ }),
2410
+ use: [orgMiddleware],
2411
+ metadata: {
2412
+ $Infer: { body: {} },
2413
+ openapi: {
2414
+ description: "Create an organization",
2415
+ responses: { "200": {
2416
+ description: "Success",
2417
+ content: { "application/json": { schema: {
2418
+ type: "object",
2419
+ description: "The organization that was created",
2420
+ $ref: "#/components/schemas/Organization"
2421
+ } } }
2422
+ } }
2423
+ }
2424
+ }
2425
+ }, async (ctx) => {
2426
+ const session = await getSessionFromCtx(ctx);
2427
+ if (!session && (ctx.request || ctx.headers)) throw new APIError("UNAUTHORIZED");
2428
+ let user = session?.user || null;
2429
+ if (!user) {
2430
+ if (!ctx.body.userId) throw new APIError("UNAUTHORIZED");
2431
+ user = await ctx.context.internalAdapter.findUserById(ctx.body.userId);
2432
+ }
2433
+ if (!user) return ctx.json(null, { status: 401 });
2434
+ const options$1 = ctx.context.orgOptions;
2435
+ if (!(typeof options$1?.allowUserToCreateOrganization === "function" ? await options$1.allowUserToCreateOrganization(user) : options$1?.allowUserToCreateOrganization === void 0 ? true : options$1.allowUserToCreateOrganization)) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_ORGANIZATION });
2436
+ const adapter = getOrgAdapter(ctx.context, options$1);
2437
+ const userOrganizations = await adapter.listOrganizations(user.id);
2438
+ if (typeof options$1.organizationLimit === "number" ? userOrganizations.length >= options$1.organizationLimit : typeof options$1.organizationLimit === "function" ? await options$1.organizationLimit(user) : false) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_HAVE_REACHED_THE_MAXIMUM_NUMBER_OF_ORGANIZATIONS });
2439
+ if (await adapter.findOrganizationBySlug(ctx.body.slug)) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_ALREADY_EXISTS });
2440
+ let { keepCurrentActiveOrganization: _, userId: __,...orgData } = ctx.body;
2441
+ if (options$1.organizationCreation?.beforeCreate) {
2442
+ const response = await options$1.organizationCreation.beforeCreate({
2443
+ organization: {
2444
+ ...orgData,
2445
+ createdAt: /* @__PURE__ */ new Date()
2446
+ },
2447
+ user
2448
+ }, ctx.request);
2449
+ if (response && typeof response === "object" && "data" in response) orgData = {
2450
+ ...ctx.body,
2451
+ ...response.data
2452
+ };
2453
+ }
2454
+ if (options$1?.organizationHooks?.beforeCreateOrganization) {
2455
+ const response = await options$1?.organizationHooks.beforeCreateOrganization({
2456
+ organization: orgData,
2457
+ user
2458
+ });
2459
+ if (response && typeof response === "object" && "data" in response) orgData = {
2460
+ ...ctx.body,
2461
+ ...response.data
2462
+ };
2463
+ }
2464
+ const organization$1 = await adapter.createOrganization({ organization: {
2465
+ ...orgData,
2466
+ createdAt: /* @__PURE__ */ new Date()
2467
+ } });
2468
+ let member;
2469
+ let teamMember = null;
2470
+ let data = {
2471
+ userId: user.id,
2472
+ organizationId: organization$1.id,
2473
+ role: ctx.context.orgOptions.creatorRole || "owner"
2474
+ };
2475
+ if (options$1?.organizationHooks?.beforeAddMember) {
2476
+ const response = await options$1?.organizationHooks.beforeAddMember({
2477
+ member: {
2478
+ userId: user.id,
2479
+ organizationId: organization$1.id,
2480
+ role: ctx.context.orgOptions.creatorRole || "owner"
2481
+ },
2482
+ user,
2483
+ organization: organization$1
2484
+ });
2485
+ if (response && typeof response === "object" && "data" in response) data = {
2486
+ ...data,
2487
+ ...response.data
2488
+ };
2489
+ }
2490
+ member = await adapter.createMember(data);
2491
+ if (options$1?.organizationHooks?.afterAddMember) await options$1?.organizationHooks.afterAddMember({
2492
+ member,
2493
+ user,
2494
+ organization: organization$1
2495
+ });
2496
+ if (options$1?.teams?.enabled && options$1.teams.defaultTeam?.enabled !== false) {
2497
+ let teamData = {
2498
+ organizationId: organization$1.id,
2499
+ name: `${organization$1.name}`,
2500
+ createdAt: /* @__PURE__ */ new Date()
2501
+ };
2502
+ if (options$1?.organizationHooks?.beforeCreateTeam) {
2503
+ const response = await options$1?.organizationHooks.beforeCreateTeam({
2504
+ team: {
2505
+ organizationId: organization$1.id,
2506
+ name: `${organization$1.name}`
2507
+ },
2508
+ user,
2509
+ organization: organization$1
2510
+ });
2511
+ if (response && typeof response === "object" && "data" in response) teamData = {
2512
+ ...teamData,
2513
+ ...response.data
2514
+ };
2515
+ }
2516
+ const defaultTeam = await options$1.teams.defaultTeam?.customCreateDefaultTeam?.(organization$1, ctx.request) || await adapter.createTeam(teamData);
2517
+ teamMember = await adapter.findOrCreateTeamMember({
2518
+ teamId: defaultTeam.id,
2519
+ userId: user.id
2520
+ });
2521
+ if (options$1?.organizationHooks?.afterCreateTeam) await options$1?.organizationHooks.afterCreateTeam({
2522
+ team: defaultTeam,
2523
+ user,
2524
+ organization: organization$1
2525
+ });
2526
+ }
2527
+ if (options$1.organizationCreation?.afterCreate) await options$1.organizationCreation.afterCreate({
2528
+ organization: organization$1,
2529
+ user,
2530
+ member
2531
+ }, ctx.request);
2532
+ if (options$1?.organizationHooks?.afterCreateOrganization) await options$1?.organizationHooks.afterCreateOrganization({
2533
+ organization: organization$1,
2534
+ user,
2535
+ member
2536
+ });
2537
+ if (ctx.context.session && !ctx.body.keepCurrentActiveOrganization) await adapter.setActiveOrganization(ctx.context.session.session.token, organization$1.id, ctx);
2538
+ if (teamMember && ctx.context.session && !ctx.body.keepCurrentActiveOrganization) await adapter.setActiveTeam(ctx.context.session.session.token, teamMember.teamId, ctx);
2539
+ return ctx.json({
2540
+ ...organization$1,
2541
+ metadata: organization$1.metadata && typeof organization$1.metadata === "string" ? JSON.parse(organization$1.metadata) : organization$1.metadata,
2542
+ members: [member]
2543
+ });
2544
+ });
2545
+ };
2546
+ const checkOrganizationSlug = (options) => createAuthEndpoint("/organization/check-slug", {
2547
+ method: "POST",
2548
+ body: z.object({ slug: z.string().meta({ description: "The organization slug to check. Eg: \"my-org\"" }) }),
2549
+ use: [requestOnlySessionMiddleware, orgMiddleware]
2550
+ }, async (ctx) => {
2551
+ if (!await getOrgAdapter(ctx.context, options).findOrganizationBySlug(ctx.body.slug)) return ctx.json({ status: true });
2552
+ throw new APIError("BAD_REQUEST", { message: "slug is taken" });
2553
+ });
2554
+ const updateOrganization = (options) => {
2555
+ const additionalFieldsSchema = toZodSchema({
2556
+ fields: options?.schema?.organization?.additionalFields || {},
2557
+ isClientSide: true
2558
+ });
2559
+ return createAuthEndpoint("/organization/update", {
2560
+ method: "POST",
2561
+ body: z.object({
2562
+ data: z.object({
2563
+ ...additionalFieldsSchema.shape,
2564
+ name: z.string().min(1).meta({ description: "The name of the organization" }).optional(),
2565
+ slug: z.string().min(1).meta({ description: "The slug of the organization" }).optional(),
2566
+ logo: z.string().meta({ description: "The logo of the organization" }).optional(),
2567
+ metadata: z.record(z.string(), z.any()).meta({ description: "The metadata of the organization" }).optional()
2568
+ }).partial(),
2569
+ organizationId: z.string().meta({ description: "The organization ID. Eg: \"org-id\"" }).optional()
2570
+ }),
2571
+ requireHeaders: true,
2572
+ use: [orgMiddleware],
2573
+ metadata: {
2574
+ $Infer: { body: {} },
2575
+ openapi: {
2576
+ description: "Update an organization",
2577
+ responses: { "200": {
2578
+ description: "Success",
2579
+ content: { "application/json": { schema: {
2580
+ type: "object",
2581
+ description: "The updated organization",
2582
+ $ref: "#/components/schemas/Organization"
2583
+ } } }
2584
+ } }
2585
+ }
2586
+ }
2587
+ }, async (ctx) => {
2588
+ const session = await ctx.context.getSession(ctx);
2589
+ if (!session) throw new APIError("UNAUTHORIZED", { message: "User not found" });
2590
+ const organizationId = ctx.body.organizationId || session.session.activeOrganizationId;
2591
+ if (!organizationId) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_NOT_FOUND });
2592
+ const adapter = getOrgAdapter(ctx.context, options);
2593
+ const member = await adapter.findMemberByOrgId({
2594
+ userId: session.user.id,
2595
+ organizationId
2596
+ });
2597
+ if (!member) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.USER_IS_NOT_A_MEMBER_OF_THE_ORGANIZATION });
2598
+ if (!await hasPermission({
2599
+ permissions: { organization: ["update"] },
2600
+ role: member.role,
2601
+ options: ctx.context.orgOptions,
2602
+ organizationId
2603
+ }, ctx)) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_ORGANIZATION });
2604
+ if (typeof ctx.body.data.slug === "string") {
2605
+ const existingOrganization = await adapter.findOrganizationBySlug(ctx.body.data.slug);
2606
+ if (existingOrganization && existingOrganization.id !== organizationId) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_SLUG_ALREADY_TAKEN });
2607
+ }
2608
+ if (options?.organizationHooks?.beforeUpdateOrganization) {
2609
+ const response = await options.organizationHooks.beforeUpdateOrganization({
2610
+ organization: ctx.body.data,
2611
+ user: session.user,
2612
+ member
2613
+ });
2614
+ if (response && typeof response === "object" && "data" in response) ctx.body.data = {
2615
+ ...ctx.body.data,
2616
+ ...response.data
2617
+ };
2618
+ }
2619
+ const updatedOrg = await adapter.updateOrganization(organizationId, ctx.body.data);
2620
+ if (options?.organizationHooks?.afterUpdateOrganization) await options.organizationHooks.afterUpdateOrganization({
2621
+ organization: updatedOrg,
2622
+ user: session.user,
2623
+ member
2624
+ });
2625
+ return ctx.json(updatedOrg);
2626
+ });
2627
+ };
2628
+ const deleteOrganization = (options) => {
2629
+ return createAuthEndpoint("/organization/delete", {
2630
+ method: "POST",
2631
+ body: z.object({ organizationId: z.string().meta({ description: "The organization id to delete" }) }),
2632
+ requireHeaders: true,
2633
+ use: [orgMiddleware],
2634
+ metadata: { openapi: {
2635
+ description: "Delete an organization",
2636
+ responses: { "200": {
2637
+ description: "Success",
2638
+ content: { "application/json": { schema: {
2639
+ type: "string",
2640
+ description: "The organization id that was deleted"
2641
+ } } }
2642
+ } }
2643
+ } }
2644
+ }, async (ctx) => {
2645
+ if (ctx.context.orgOptions.organizationDeletion?.disabled || ctx.context.orgOptions.disableOrganizationDeletion) {
2646
+ if (ctx.context.orgOptions.organizationDeletion?.disabled) ctx.context.logger.info("`organizationDeletion.disabled` is deprecated. Use `disableOrganizationDeletion` instead");
2647
+ throw new APIError("NOT_FOUND", { message: "Organization deletion is disabled" });
2648
+ }
2649
+ const session = await ctx.context.getSession(ctx);
2650
+ if (!session) throw new APIError("UNAUTHORIZED", { status: 401 });
2651
+ const organizationId = ctx.body.organizationId;
2652
+ if (!organizationId) return ctx.json(null, {
2653
+ status: 400,
2654
+ body: { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_NOT_FOUND }
2655
+ });
2656
+ const adapter = getOrgAdapter(ctx.context, options);
2657
+ const member = await adapter.findMemberByOrgId({
2658
+ userId: session.user.id,
2659
+ organizationId
2660
+ });
2661
+ if (!member) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.USER_IS_NOT_A_MEMBER_OF_THE_ORGANIZATION });
2662
+ if (!await hasPermission({
2663
+ role: member.role,
2664
+ permissions: { organization: ["delete"] },
2665
+ organizationId,
2666
+ options: ctx.context.orgOptions
2667
+ }, ctx)) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_ORGANIZATION });
2668
+ if (organizationId === session.session.activeOrganizationId)
2669
+ /**
2670
+ * If the organization is deleted, we set the active organization to null
2671
+ */
2672
+ await adapter.setActiveOrganization(session.session.token, null, ctx);
2673
+ const org = await adapter.findOrganizationById(organizationId);
2674
+ if (!org) throw new APIError("BAD_REQUEST");
2675
+ if (options?.organizationHooks?.beforeDeleteOrganization) await options.organizationHooks.beforeDeleteOrganization({
2676
+ organization: org,
2677
+ user: session.user
2678
+ });
2679
+ await adapter.deleteOrganization(organizationId);
2680
+ if (options?.organizationHooks?.afterDeleteOrganization) await options.organizationHooks.afterDeleteOrganization({
2681
+ organization: org,
2682
+ user: session.user
2683
+ });
2684
+ return ctx.json(org);
2685
+ });
2686
+ };
2687
+ const getFullOrganization = (options) => createAuthEndpoint("/organization/get-full-organization", {
2688
+ method: "GET",
2689
+ query: z.optional(z.object({
2690
+ organizationId: z.string().meta({ description: "The organization id to get" }).optional(),
2691
+ organizationSlug: z.string().meta({ description: "The organization slug to get" }).optional(),
2692
+ membersLimit: z.number().or(z.string().transform((val) => parseInt(val))).meta({ description: "The limit of members to get. By default, it uses the membershipLimit option which defaults to 100." }).optional()
2693
+ })),
2694
+ requireHeaders: true,
2695
+ use: [orgMiddleware, orgSessionMiddleware],
2696
+ metadata: { openapi: {
2697
+ description: "Get the full organization",
2698
+ responses: { "200": {
2699
+ description: "Success",
2700
+ content: { "application/json": { schema: {
2701
+ type: "object",
2702
+ description: "The organization",
2703
+ $ref: "#/components/schemas/Organization"
2704
+ } } }
2705
+ } }
2706
+ } }
2707
+ }, async (ctx) => {
2708
+ const session = ctx.context.session;
2709
+ const organizationId = ctx.query?.organizationSlug || ctx.query?.organizationId || session.session.activeOrganizationId;
2710
+ if (!organizationId) return ctx.json(null, { status: 200 });
2711
+ const adapter = getOrgAdapter(ctx.context, options);
2712
+ const organization$1 = await adapter.findFullOrganization({
2713
+ organizationId,
2714
+ isSlug: !!ctx.query?.organizationSlug,
2715
+ includeTeams: ctx.context.orgOptions.teams?.enabled,
2716
+ membersLimit: ctx.query?.membersLimit
2717
+ });
2718
+ if (!organization$1) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_NOT_FOUND });
2719
+ if (!await adapter.checkMembership({
2720
+ userId: session.user.id,
2721
+ organizationId: organization$1.id
2722
+ })) {
2723
+ await adapter.setActiveOrganization(session.session.token, null, ctx);
2724
+ throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.USER_IS_NOT_A_MEMBER_OF_THE_ORGANIZATION });
2725
+ }
2726
+ return ctx.json(organization$1);
2727
+ });
2728
+ const setActiveOrganization = (options) => {
2729
+ return createAuthEndpoint("/organization/set-active", {
2730
+ method: "POST",
2731
+ body: z.object({
2732
+ organizationId: z.string().meta({ description: "The organization id to set as active. It can be null to unset the active organization. Eg: \"org-id\"" }).nullable().optional(),
2733
+ organizationSlug: z.string().meta({ description: "The organization slug to set as active. It can be null to unset the active organization if organizationId is not provided. Eg: \"org-slug\"" }).optional()
2734
+ }),
2735
+ use: [orgSessionMiddleware, orgMiddleware],
2736
+ metadata: { openapi: {
2737
+ description: "Set the active organization",
2738
+ responses: { "200": {
2739
+ description: "Success",
2740
+ content: { "application/json": { schema: {
2741
+ type: "object",
2742
+ description: "The organization",
2743
+ $ref: "#/components/schemas/Organization"
2744
+ } } }
2745
+ } }
2746
+ } }
2747
+ }, async (ctx) => {
2748
+ const adapter = getOrgAdapter(ctx.context, options);
2749
+ const session = ctx.context.session;
2750
+ let organizationId = ctx.body.organizationId;
2751
+ let organizationSlug = ctx.body.organizationSlug;
2752
+ if (organizationId === null) {
2753
+ if (!session.session.activeOrganizationId) return ctx.json(null);
2754
+ await setSessionCookie(ctx, {
2755
+ session: await adapter.setActiveOrganization(session.session.token, null, ctx),
2756
+ user: session.user
2757
+ });
2758
+ return ctx.json(null);
2759
+ }
2760
+ if (!organizationId && !organizationSlug) {
2761
+ const sessionOrgId = session.session.activeOrganizationId;
2762
+ if (!sessionOrgId) return ctx.json(null);
2763
+ organizationId = sessionOrgId;
2764
+ }
2765
+ if (organizationSlug && !organizationId) {
2766
+ const organization$2 = await adapter.findOrganizationBySlug(organizationSlug);
2767
+ if (!organization$2) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_NOT_FOUND });
2768
+ organizationId = organization$2.id;
2769
+ }
2770
+ if (!organizationId) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_NOT_FOUND });
2771
+ if (!await adapter.checkMembership({
2772
+ userId: session.user.id,
2773
+ organizationId
2774
+ })) {
2775
+ await adapter.setActiveOrganization(session.session.token, null, ctx);
2776
+ throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.USER_IS_NOT_A_MEMBER_OF_THE_ORGANIZATION });
2777
+ }
2778
+ let organization$1 = await adapter.findOrganizationById(organizationId);
2779
+ if (!organization$1) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_NOT_FOUND });
2780
+ await setSessionCookie(ctx, {
2781
+ session: await adapter.setActiveOrganization(session.session.token, organization$1.id, ctx),
2782
+ user: session.user
2783
+ });
2784
+ return ctx.json(organization$1);
2785
+ });
2786
+ };
2787
+ const listOrganizations = (options) => createAuthEndpoint("/organization/list", {
2788
+ method: "GET",
2789
+ use: [orgMiddleware, orgSessionMiddleware],
2790
+ metadata: { openapi: {
2791
+ description: "List all organizations",
2792
+ responses: { "200": {
2793
+ description: "Success",
2794
+ content: { "application/json": { schema: {
2795
+ type: "array",
2796
+ items: { $ref: "#/components/schemas/Organization" }
2797
+ } } }
2798
+ } }
2799
+ } }
2800
+ }, async (ctx) => {
2801
+ const organizations = await getOrgAdapter(ctx.context, options).listOrganizations(ctx.context.session.user.id);
2802
+ return ctx.json(organizations);
2803
+ });
2804
+
2805
+ //#endregion
2806
+ //#region src/plugins/organization/routes/crud-team.ts
2807
+ const createTeam = (options) => {
2808
+ const additionalFieldsSchema = toZodSchema({
2809
+ fields: options?.schema?.team?.additionalFields ?? {},
2810
+ isClientSide: true
2811
+ });
2812
+ const baseSchema = z$1.object({
2813
+ name: z$1.string().meta({ description: "The name of the team. Eg: \"my-team\"" }),
2814
+ organizationId: z$1.string().meta({ description: "The organization ID which the team will be created in. Defaults to the active organization. Eg: \"organization-id\"" }).optional()
2815
+ });
2816
+ return createAuthEndpoint("/organization/create-team", {
2817
+ method: "POST",
2818
+ body: z$1.object({
2819
+ ...baseSchema.shape,
2820
+ ...additionalFieldsSchema.shape
2821
+ }),
2822
+ use: [orgMiddleware],
2823
+ metadata: {
2824
+ $Infer: { body: {} },
2825
+ openapi: {
2826
+ description: "Create a new team within an organization",
2827
+ responses: { "200": {
2828
+ description: "Team created successfully",
2829
+ content: { "application/json": { schema: {
2830
+ type: "object",
2831
+ properties: {
2832
+ id: {
2833
+ type: "string",
2834
+ description: "Unique identifier of the created team"
2835
+ },
2836
+ name: {
2837
+ type: "string",
2838
+ description: "Name of the team"
2839
+ },
2840
+ organizationId: {
2841
+ type: "string",
2842
+ description: "ID of the organization the team belongs to"
2843
+ },
2844
+ createdAt: {
2845
+ type: "string",
2846
+ format: "date-time",
2847
+ description: "Timestamp when the team was created"
2848
+ },
2849
+ updatedAt: {
2850
+ type: "string",
2851
+ format: "date-time",
2852
+ description: "Timestamp when the team was last updated"
2853
+ }
2854
+ },
2855
+ required: [
2856
+ "id",
2857
+ "name",
2858
+ "organizationId",
2859
+ "createdAt",
2860
+ "updatedAt"
2861
+ ]
2862
+ } } }
2863
+ } }
2864
+ }
2865
+ }
2866
+ }, async (ctx) => {
2867
+ const session = await getSessionFromCtx(ctx);
2868
+ const organizationId = ctx.body.organizationId || session?.session.activeOrganizationId;
2869
+ if (!session && (ctx.request || ctx.headers)) throw new APIError("UNAUTHORIZED");
2870
+ if (!organizationId) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.NO_ACTIVE_ORGANIZATION });
2871
+ const adapter = getOrgAdapter(ctx.context, options);
2872
+ if (session) {
2873
+ const member = await adapter.findMemberByOrgId({
2874
+ userId: session.user.id,
2875
+ organizationId
2876
+ });
2877
+ if (!member) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_INVITE_USERS_TO_THIS_ORGANIZATION });
2878
+ if (!await hasPermission({
2879
+ role: member.role,
2880
+ options: ctx.context.orgOptions,
2881
+ permissions: { team: ["create"] },
2882
+ organizationId
2883
+ }, ctx)) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_CREATE_TEAMS_IN_THIS_ORGANIZATION });
2884
+ }
2885
+ const existingTeams = await adapter.listTeams(organizationId);
2886
+ const maximum = typeof ctx.context.orgOptions.teams?.maximumTeams === "function" ? await ctx.context.orgOptions.teams?.maximumTeams({
2887
+ organizationId,
2888
+ session
2889
+ }, ctx.request) : ctx.context.orgOptions.teams?.maximumTeams;
2890
+ if (maximum ? existingTeams.length >= maximum : false) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.YOU_HAVE_REACHED_THE_MAXIMUM_NUMBER_OF_TEAMS });
2891
+ const { name, organizationId: _,...additionalFields } = ctx.body;
2892
+ const organization$1 = await adapter.findOrganizationById(organizationId);
2893
+ if (!organization$1) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_NOT_FOUND });
2894
+ let teamData = {
2895
+ name,
2896
+ organizationId,
2897
+ createdAt: /* @__PURE__ */ new Date(),
2898
+ updatedAt: /* @__PURE__ */ new Date(),
2899
+ ...additionalFields
2900
+ };
2901
+ if (options?.organizationHooks?.beforeCreateTeam) {
2902
+ const response = await options?.organizationHooks.beforeCreateTeam({
2903
+ team: {
2904
+ name,
2905
+ organizationId,
2906
+ ...additionalFields
2907
+ },
2908
+ user: session?.user,
2909
+ organization: organization$1
2910
+ });
2911
+ if (response && typeof response === "object" && "data" in response) teamData = {
2912
+ ...teamData,
2913
+ ...response.data
2914
+ };
2915
+ }
2916
+ const createdTeam = await adapter.createTeam(teamData);
2917
+ if (options?.organizationHooks?.afterCreateTeam) await options?.organizationHooks.afterCreateTeam({
2918
+ team: createdTeam,
2919
+ user: session?.user,
2920
+ organization: organization$1
2921
+ });
2922
+ return ctx.json(createdTeam);
2923
+ });
2924
+ };
2925
+ const removeTeam = (options) => createAuthEndpoint("/organization/remove-team", {
2926
+ method: "POST",
2927
+ body: z$1.object({
2928
+ teamId: z$1.string().meta({ description: `The team ID of the team to remove. Eg: "team-id"` }),
2929
+ organizationId: z$1.string().meta({ description: `The organization ID which the team falls under. If not provided, it will default to the user's active organization. Eg: "organization-id"` }).optional()
2930
+ }),
2931
+ use: [orgMiddleware],
2932
+ metadata: { openapi: {
2933
+ description: "Remove a team from an organization",
2934
+ responses: { "200": {
2935
+ description: "Team removed successfully",
2936
+ content: { "application/json": { schema: {
2937
+ type: "object",
2938
+ properties: { message: {
2939
+ type: "string",
2940
+ description: "Confirmation message indicating successful removal",
2941
+ enum: ["Team removed successfully."]
2942
+ } },
2943
+ required: ["message"]
2944
+ } } }
2945
+ } }
2946
+ } }
2947
+ }, async (ctx) => {
2948
+ const session = await getSessionFromCtx(ctx);
2949
+ const organizationId = ctx.body.organizationId || session?.session.activeOrganizationId;
2950
+ if (!organizationId) return ctx.json(null, {
2951
+ status: 400,
2952
+ body: { message: ORGANIZATION_ERROR_CODES.NO_ACTIVE_ORGANIZATION }
2953
+ });
2954
+ if (!session && (ctx.request || ctx.headers)) throw new APIError("UNAUTHORIZED");
2955
+ const adapter = getOrgAdapter(ctx.context, options);
2956
+ if (session) {
2957
+ const member = await adapter.findMemberByOrgId({
2958
+ userId: session.user.id,
2959
+ organizationId
2960
+ });
2961
+ if (!member || session.session?.activeTeamId === ctx.body.teamId) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_TEAM });
2962
+ if (!await hasPermission({
2963
+ role: member.role,
2964
+ options: ctx.context.orgOptions,
2965
+ permissions: { team: ["delete"] },
2966
+ organizationId
2967
+ }, ctx)) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_DELETE_TEAMS_IN_THIS_ORGANIZATION });
2968
+ }
2969
+ const team = await adapter.findTeamById({
2970
+ teamId: ctx.body.teamId,
2971
+ organizationId
2972
+ });
2973
+ if (!team || team.organizationId !== organizationId) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.TEAM_NOT_FOUND });
2974
+ if (!ctx.context.orgOptions.teams?.allowRemovingAllTeams) {
2975
+ if ((await adapter.listTeams(organizationId)).length <= 1) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.UNABLE_TO_REMOVE_LAST_TEAM });
2976
+ }
2977
+ const organization$1 = await adapter.findOrganizationById(organizationId);
2978
+ if (!organization$1) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_NOT_FOUND });
2979
+ if (options?.organizationHooks?.beforeDeleteTeam) await options?.organizationHooks.beforeDeleteTeam({
2980
+ team,
2981
+ user: session?.user,
2982
+ organization: organization$1
2983
+ });
2984
+ await adapter.deleteTeam(team.id);
2985
+ if (options?.organizationHooks?.afterDeleteTeam) await options?.organizationHooks.afterDeleteTeam({
2986
+ team,
2987
+ user: session?.user,
2988
+ organization: organization$1
2989
+ });
2990
+ return ctx.json({ message: "Team removed successfully." });
2991
+ });
2992
+ const updateTeam = (options) => {
2993
+ const additionalFieldsSchema = toZodSchema({
2994
+ fields: options?.schema?.team?.additionalFields ?? {},
2995
+ isClientSide: true
2996
+ });
2997
+ return createAuthEndpoint("/organization/update-team", {
2998
+ method: "POST",
2999
+ body: z$1.object({
3000
+ teamId: z$1.string().meta({ description: `The ID of the team to be updated. Eg: "team-id"` }),
3001
+ data: z$1.object({
3002
+ ...teamSchema.shape,
3003
+ ...additionalFieldsSchema.shape
3004
+ }).partial()
3005
+ }),
3006
+ requireHeaders: true,
3007
+ use: [orgMiddleware, orgSessionMiddleware],
3008
+ metadata: {
3009
+ $Infer: { body: {} },
3010
+ openapi: {
3011
+ description: "Update an existing team in an organization",
3012
+ responses: { "200": {
3013
+ description: "Team updated successfully",
3014
+ content: { "application/json": { schema: {
3015
+ type: "object",
3016
+ properties: {
3017
+ id: {
3018
+ type: "string",
3019
+ description: "Unique identifier of the updated team"
3020
+ },
3021
+ name: {
3022
+ type: "string",
3023
+ description: "Updated name of the team"
3024
+ },
3025
+ organizationId: {
3026
+ type: "string",
3027
+ description: "ID of the organization the team belongs to"
3028
+ },
3029
+ createdAt: {
3030
+ type: "string",
3031
+ format: "date-time",
3032
+ description: "Timestamp when the team was created"
3033
+ },
3034
+ updatedAt: {
3035
+ type: "string",
3036
+ format: "date-time",
3037
+ description: "Timestamp when the team was last updated"
3038
+ }
3039
+ },
3040
+ required: [
3041
+ "id",
3042
+ "name",
3043
+ "organizationId",
3044
+ "createdAt",
3045
+ "updatedAt"
3046
+ ]
3047
+ } } }
3048
+ } }
3049
+ }
3050
+ }
3051
+ }, async (ctx) => {
3052
+ const session = ctx.context.session;
3053
+ const organizationId = ctx.body.data.organizationId || session.session.activeOrganizationId;
3054
+ if (!organizationId) return ctx.json(null, {
3055
+ status: 400,
3056
+ body: { message: ORGANIZATION_ERROR_CODES.NO_ACTIVE_ORGANIZATION }
3057
+ });
3058
+ const adapter = getOrgAdapter(ctx.context, options);
3059
+ const member = await adapter.findMemberByOrgId({
3060
+ userId: session.user.id,
3061
+ organizationId
3062
+ });
3063
+ if (!member) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_TEAM });
3064
+ if (!await hasPermission({
3065
+ role: member.role,
3066
+ options: ctx.context.orgOptions,
3067
+ permissions: { team: ["update"] },
3068
+ organizationId
3069
+ }, ctx)) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_TEAM });
3070
+ const team = await adapter.findTeamById({
3071
+ teamId: ctx.body.teamId,
3072
+ organizationId
3073
+ });
3074
+ if (!team || team.organizationId !== organizationId) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.TEAM_NOT_FOUND });
3075
+ const { name, organizationId: __,...additionalFields } = ctx.body.data;
3076
+ const organization$1 = await adapter.findOrganizationById(organizationId);
3077
+ if (!organization$1) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_NOT_FOUND });
3078
+ const updates = {
3079
+ name,
3080
+ ...additionalFields
3081
+ };
3082
+ if (options?.organizationHooks?.beforeUpdateTeam) {
3083
+ const response = await options?.organizationHooks.beforeUpdateTeam({
3084
+ team,
3085
+ updates,
3086
+ user: session.user,
3087
+ organization: organization$1
3088
+ });
3089
+ if (response && typeof response === "object" && "data" in response) {
3090
+ const modifiedUpdates = response.data;
3091
+ const updatedTeam$1 = await adapter.updateTeam(team.id, modifiedUpdates);
3092
+ if (options?.organizationHooks?.afterUpdateTeam) await options?.organizationHooks.afterUpdateTeam({
3093
+ team: updatedTeam$1,
3094
+ user: session.user,
3095
+ organization: organization$1
3096
+ });
3097
+ return ctx.json(updatedTeam$1);
3098
+ }
3099
+ }
3100
+ const updatedTeam = await adapter.updateTeam(team.id, updates);
3101
+ if (options?.organizationHooks?.afterUpdateTeam) await options?.organizationHooks.afterUpdateTeam({
3102
+ team: updatedTeam,
3103
+ user: session.user,
3104
+ organization: organization$1
3105
+ });
3106
+ return ctx.json(updatedTeam);
3107
+ });
3108
+ };
3109
+ const listOrganizationTeams = (options) => createAuthEndpoint("/organization/list-teams", {
3110
+ method: "GET",
3111
+ query: z$1.optional(z$1.object({ organizationId: z$1.string().meta({ description: `The organization ID which the teams are under to list. Defaults to the users active organization. Eg: "organziation-id"` }).optional() })),
3112
+ requireHeaders: true,
3113
+ metadata: { openapi: {
3114
+ description: "List all teams in an organization",
3115
+ responses: { "200": {
3116
+ description: "Teams retrieved successfully",
3117
+ content: { "application/json": { schema: {
3118
+ type: "array",
3119
+ items: {
3120
+ type: "object",
3121
+ properties: {
3122
+ id: {
3123
+ type: "string",
3124
+ description: "Unique identifier of the team"
3125
+ },
3126
+ name: {
3127
+ type: "string",
3128
+ description: "Name of the team"
3129
+ },
3130
+ organizationId: {
3131
+ type: "string",
3132
+ description: "ID of the organization the team belongs to"
3133
+ },
3134
+ createdAt: {
3135
+ type: "string",
3136
+ format: "date-time",
3137
+ description: "Timestamp when the team was created"
3138
+ },
3139
+ updatedAt: {
3140
+ type: "string",
3141
+ format: "date-time",
3142
+ description: "Timestamp when the team was last updated"
3143
+ }
3144
+ },
3145
+ required: [
3146
+ "id",
3147
+ "name",
3148
+ "organizationId",
3149
+ "createdAt",
3150
+ "updatedAt"
3151
+ ]
3152
+ },
3153
+ description: "Array of team objects within the organization"
3154
+ } } }
3155
+ } }
3156
+ } },
3157
+ use: [orgMiddleware, orgSessionMiddleware]
3158
+ }, async (ctx) => {
3159
+ const session = ctx.context.session;
3160
+ const organizationId = ctx.query?.organizationId || session?.session.activeOrganizationId;
3161
+ if (!organizationId) throw ctx.error("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.NO_ACTIVE_ORGANIZATION });
3162
+ const adapter = getOrgAdapter(ctx.context, options);
3163
+ if (!await adapter.findMemberByOrgId({
3164
+ userId: session.user.id,
3165
+ organizationId: organizationId || ""
3166
+ })) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_ACCESS_THIS_ORGANIZATION });
3167
+ const teams = await adapter.listTeams(organizationId);
3168
+ return ctx.json(teams);
3169
+ });
3170
+ const setActiveTeam = (options) => createAuthEndpoint("/organization/set-active-team", {
3171
+ method: "POST",
3172
+ body: z$1.object({ teamId: z$1.string().meta({ description: "The team id to set as active. It can be null to unset the active team" }).nullable().optional() }),
3173
+ use: [orgSessionMiddleware, orgMiddleware],
3174
+ metadata: { openapi: {
3175
+ description: "Set the active team",
3176
+ responses: { "200": {
3177
+ description: "Success",
3178
+ content: { "application/json": { schema: {
3179
+ type: "object",
3180
+ description: "The team",
3181
+ $ref: "#/components/schemas/Team"
3182
+ } } }
3183
+ } }
3184
+ } }
3185
+ }, async (ctx) => {
3186
+ const adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);
3187
+ const session = ctx.context.session;
3188
+ if (ctx.body.teamId === null) {
3189
+ if (!session.session.activeTeamId) return ctx.json(null);
3190
+ await setSessionCookie(ctx, {
3191
+ session: await adapter.setActiveTeam(session.session.token, null, ctx),
3192
+ user: session.user
3193
+ });
3194
+ return ctx.json(null);
3195
+ }
3196
+ let teamId;
3197
+ if (!ctx.body.teamId) {
3198
+ const sessionTeamId = session.session.activeTeamId;
3199
+ if (!sessionTeamId) return ctx.json(null);
3200
+ else teamId = sessionTeamId;
3201
+ } else teamId = ctx.body.teamId;
3202
+ const team = await adapter.findTeamById({ teamId });
3203
+ if (!team) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.TEAM_NOT_FOUND });
3204
+ if (!await adapter.findTeamMember({
3205
+ teamId,
3206
+ userId: session.user.id
3207
+ })) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.USER_IS_NOT_A_MEMBER_OF_THE_TEAM });
3208
+ await setSessionCookie(ctx, {
3209
+ session: await adapter.setActiveTeam(session.session.token, team.id, ctx),
3210
+ user: session.user
3211
+ });
3212
+ return ctx.json(team);
3213
+ });
3214
+ const listUserTeams = (options) => createAuthEndpoint("/organization/list-user-teams", {
3215
+ method: "GET",
3216
+ metadata: { openapi: {
3217
+ description: "List all teams that the current user is a part of.",
3218
+ responses: { "200": {
3219
+ description: "Teams retrieved successfully",
3220
+ content: { "application/json": { schema: {
3221
+ type: "array",
3222
+ items: {
3223
+ type: "object",
3224
+ description: "The team",
3225
+ $ref: "#/components/schemas/Team"
3226
+ },
3227
+ description: "Array of team objects within the organization"
3228
+ } } }
3229
+ } }
3230
+ } },
3231
+ use: [orgMiddleware, orgSessionMiddleware]
3232
+ }, async (ctx) => {
3233
+ const session = ctx.context.session;
3234
+ const teams = await getOrgAdapter(ctx.context, ctx.context.orgOptions).listTeamsByUser({ userId: session.user.id });
3235
+ return ctx.json(teams);
3236
+ });
3237
+ const listTeamMembers = (options) => createAuthEndpoint("/organization/list-team-members", {
3238
+ method: "GET",
3239
+ query: z$1.optional(z$1.object({ teamId: z$1.string().optional().meta({ description: "The team whose members we should return. If this is not provided the members of the current active team get returned." }) })),
3240
+ metadata: { openapi: {
3241
+ description: "List the members of the given team.",
3242
+ responses: { "200": {
3243
+ description: "Teams retrieved successfully",
3244
+ content: { "application/json": { schema: {
3245
+ type: "array",
3246
+ items: {
3247
+ type: "object",
3248
+ description: "The team member",
3249
+ properties: {
3250
+ id: {
3251
+ type: "string",
3252
+ description: "Unique identifier of the team member"
3253
+ },
3254
+ userId: {
3255
+ type: "string",
3256
+ description: "The user ID of the team member"
3257
+ },
3258
+ teamId: {
3259
+ type: "string",
3260
+ description: "The team ID of the team the team member is in"
3261
+ },
3262
+ createdAt: {
3263
+ type: "string",
3264
+ format: "date-time",
3265
+ description: "Timestamp when the team member was created"
3266
+ }
3267
+ },
3268
+ required: [
3269
+ "id",
3270
+ "userId",
3271
+ "teamId",
3272
+ "createdAt"
3273
+ ]
3274
+ },
3275
+ description: "Array of team member objects within the team"
3276
+ } } }
3277
+ } }
3278
+ } },
3279
+ use: [orgMiddleware, orgSessionMiddleware]
3280
+ }, async (ctx) => {
3281
+ const session = ctx.context.session;
3282
+ const adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);
3283
+ let teamId = ctx.query?.teamId || session?.session.activeTeamId;
3284
+ if (!teamId) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.YOU_DO_NOT_HAVE_AN_ACTIVE_TEAM });
3285
+ if (!await adapter.findTeamMember({
3286
+ userId: session.user.id,
3287
+ teamId
3288
+ })) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.USER_IS_NOT_A_MEMBER_OF_THE_TEAM });
3289
+ const members = await adapter.listTeamMembers({ teamId });
3290
+ return ctx.json(members);
3291
+ });
3292
+ const addTeamMember = (options) => createAuthEndpoint("/organization/add-team-member", {
3293
+ method: "POST",
3294
+ body: z$1.object({
3295
+ teamId: z$1.string().meta({ description: "The team the user should be a member of." }),
3296
+ userId: z$1.coerce.string().meta({ description: "The user Id which represents the user to be added as a member." })
3297
+ }),
3298
+ metadata: { openapi: {
3299
+ description: "The newly created member",
3300
+ responses: { "200": {
3301
+ description: "Team member created successfully",
3302
+ content: { "application/json": { schema: {
3303
+ type: "object",
3304
+ description: "The team member",
3305
+ properties: {
3306
+ id: {
3307
+ type: "string",
3308
+ description: "Unique identifier of the team member"
3309
+ },
3310
+ userId: {
3311
+ type: "string",
3312
+ description: "The user ID of the team member"
3313
+ },
3314
+ teamId: {
3315
+ type: "string",
3316
+ description: "The team ID of the team the team member is in"
3317
+ },
3318
+ createdAt: {
3319
+ type: "string",
3320
+ format: "date-time",
3321
+ description: "Timestamp when the team member was created"
3322
+ }
3323
+ },
3324
+ required: [
3325
+ "id",
3326
+ "userId",
3327
+ "teamId",
3328
+ "createdAt"
3329
+ ]
3330
+ } } }
3331
+ } }
3332
+ } },
3333
+ use: [orgMiddleware, orgSessionMiddleware]
3334
+ }, async (ctx) => {
3335
+ const session = ctx.context.session;
3336
+ const adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);
3337
+ if (!session.session.activeOrganizationId) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.NO_ACTIVE_ORGANIZATION });
3338
+ const currentMember = await adapter.findMemberByOrgId({
3339
+ userId: session.user.id,
3340
+ organizationId: session.session.activeOrganizationId
3341
+ });
3342
+ if (!currentMember) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.USER_IS_NOT_A_MEMBER_OF_THE_ORGANIZATION });
3343
+ if (!await hasPermission({
3344
+ role: currentMember.role,
3345
+ options: ctx.context.orgOptions,
3346
+ permissions: { member: ["update"] },
3347
+ organizationId: session.session.activeOrganizationId
3348
+ }, ctx)) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_CREATE_A_NEW_TEAM_MEMBER });
3349
+ if (!await adapter.findMemberByOrgId({
3350
+ userId: ctx.body.userId,
3351
+ organizationId: session.session.activeOrganizationId
3352
+ })) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.USER_IS_NOT_A_MEMBER_OF_THE_ORGANIZATION });
3353
+ const team = await adapter.findTeamById({
3354
+ teamId: ctx.body.teamId,
3355
+ organizationId: session.session.activeOrganizationId
3356
+ });
3357
+ if (!team) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.TEAM_NOT_FOUND });
3358
+ const organization$1 = await adapter.findOrganizationById(session.session.activeOrganizationId);
3359
+ if (!organization$1) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_NOT_FOUND });
3360
+ const userBeingAdded = await ctx.context.internalAdapter.findUserById(ctx.body.userId);
3361
+ if (!userBeingAdded) throw new APIError("BAD_REQUEST", { message: "User not found" });
3362
+ if (options?.organizationHooks?.beforeAddTeamMember) {
3363
+ const response = await options?.organizationHooks.beforeAddTeamMember({
3364
+ teamMember: {
3365
+ teamId: ctx.body.teamId,
3366
+ userId: ctx.body.userId
3367
+ },
3368
+ team,
3369
+ user: userBeingAdded,
3370
+ organization: organization$1
3371
+ });
3372
+ if (response && typeof response === "object" && "data" in response) {}
3373
+ }
3374
+ const teamMember = await adapter.findOrCreateTeamMember({
3375
+ teamId: ctx.body.teamId,
3376
+ userId: ctx.body.userId
3377
+ });
3378
+ if (options?.organizationHooks?.afterAddTeamMember) await options?.organizationHooks.afterAddTeamMember({
3379
+ teamMember,
3380
+ team,
3381
+ user: userBeingAdded,
3382
+ organization: organization$1
3383
+ });
3384
+ return ctx.json(teamMember);
3385
+ });
3386
+ const removeTeamMember = (options) => createAuthEndpoint("/organization/remove-team-member", {
3387
+ method: "POST",
3388
+ body: z$1.object({
3389
+ teamId: z$1.string().meta({ description: "The team the user should be removed from." }),
3390
+ userId: z$1.coerce.string().meta({ description: "The user which should be removed from the team." })
3391
+ }),
3392
+ metadata: { openapi: {
3393
+ description: "Remove a member from a team",
3394
+ responses: { "200": {
3395
+ description: "Team member removed successfully",
3396
+ content: { "application/json": { schema: {
3397
+ type: "object",
3398
+ properties: { message: {
3399
+ type: "string",
3400
+ description: "Confirmation message indicating successful removal",
3401
+ enum: ["Team member removed successfully."]
3402
+ } },
3403
+ required: ["message"]
3404
+ } } }
3405
+ } }
3406
+ } },
3407
+ use: [orgMiddleware, orgSessionMiddleware]
3408
+ }, async (ctx) => {
3409
+ const session = ctx.context.session;
3410
+ const adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);
3411
+ if (!session.session.activeOrganizationId) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.NO_ACTIVE_ORGANIZATION });
3412
+ const currentMember = await adapter.findMemberByOrgId({
3413
+ userId: session.user.id,
3414
+ organizationId: session.session.activeOrganizationId
3415
+ });
3416
+ if (!currentMember) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.USER_IS_NOT_A_MEMBER_OF_THE_ORGANIZATION });
3417
+ if (!await hasPermission({
3418
+ role: currentMember.role,
3419
+ options: ctx.context.orgOptions,
3420
+ permissions: { member: ["delete"] },
3421
+ organizationId: session.session.activeOrganizationId
3422
+ }, ctx)) throw new APIError("FORBIDDEN", { message: ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_REMOVE_A_TEAM_MEMBER });
3423
+ if (!await adapter.findMemberByOrgId({
3424
+ userId: ctx.body.userId,
3425
+ organizationId: session.session.activeOrganizationId
3426
+ })) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.USER_IS_NOT_A_MEMBER_OF_THE_ORGANIZATION });
3427
+ const team = await adapter.findTeamById({
3428
+ teamId: ctx.body.teamId,
3429
+ organizationId: session.session.activeOrganizationId
3430
+ });
3431
+ if (!team) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.TEAM_NOT_FOUND });
3432
+ const organization$1 = await adapter.findOrganizationById(session.session.activeOrganizationId);
3433
+ if (!organization$1) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.ORGANIZATION_NOT_FOUND });
3434
+ const userBeingRemoved = await ctx.context.internalAdapter.findUserById(ctx.body.userId);
3435
+ if (!userBeingRemoved) throw new APIError("BAD_REQUEST", { message: "User not found" });
3436
+ const teamMember = await adapter.findTeamMember({
3437
+ teamId: ctx.body.teamId,
3438
+ userId: ctx.body.userId
3439
+ });
3440
+ if (!teamMember) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.USER_IS_NOT_A_MEMBER_OF_THE_TEAM });
3441
+ if (options?.organizationHooks?.beforeRemoveTeamMember) await options?.organizationHooks.beforeRemoveTeamMember({
3442
+ teamMember,
3443
+ team,
3444
+ user: userBeingRemoved,
3445
+ organization: organization$1
3446
+ });
3447
+ await adapter.removeTeamMember({
3448
+ teamId: ctx.body.teamId,
3449
+ userId: ctx.body.userId
3450
+ });
3451
+ if (options?.organizationHooks?.afterRemoveTeamMember) await options?.organizationHooks.afterRemoveTeamMember({
3452
+ teamMember,
3453
+ team,
3454
+ user: userBeingRemoved,
3455
+ organization: organization$1
3456
+ });
3457
+ return ctx.json({ message: "Team member removed successfully." });
3458
+ });
3459
+
3460
+ //#endregion
3461
+ //#region src/plugins/organization/organization.ts
3462
+ function parseRoles(roles) {
3463
+ return Array.isArray(roles) ? roles.join(",") : roles;
3464
+ }
3465
+ const createHasPermission = (options) => {
3466
+ return createAuthEndpoint("/organization/has-permission", {
3467
+ method: "POST",
3468
+ requireHeaders: true,
3469
+ body: z$1.object({ organizationId: z$1.string().optional() }).and(z$1.union([z$1.object({
3470
+ permission: z$1.record(z$1.string(), z$1.array(z$1.string())),
3471
+ permissions: z$1.undefined()
3472
+ }), z$1.object({
3473
+ permission: z$1.undefined(),
3474
+ permissions: z$1.record(z$1.string(), z$1.array(z$1.string()))
3475
+ })])),
3476
+ use: [orgSessionMiddleware],
3477
+ metadata: {
3478
+ $Infer: { body: {} },
3479
+ openapi: {
3480
+ description: "Check if the user has permission",
3481
+ requestBody: { content: { "application/json": { schema: {
3482
+ type: "object",
3483
+ properties: {
3484
+ permission: {
3485
+ type: "object",
3486
+ description: "The permission to check",
3487
+ deprecated: true
3488
+ },
3489
+ permissions: {
3490
+ type: "object",
3491
+ description: "The permission to check"
3492
+ }
3493
+ },
3494
+ required: ["permissions"]
3495
+ } } } },
3496
+ responses: { "200": {
3497
+ description: "Success",
3498
+ content: { "application/json": { schema: {
3499
+ type: "object",
3500
+ properties: {
3501
+ error: { type: "string" },
3502
+ success: { type: "boolean" }
3503
+ },
3504
+ required: ["success"]
3505
+ } } }
3506
+ } }
3507
+ }
3508
+ }
3509
+ }, async (ctx) => {
3510
+ const activeOrganizationId = ctx.body.organizationId || ctx.context.session.session.activeOrganizationId;
3511
+ if (!activeOrganizationId) throw new APIError("BAD_REQUEST", { message: ORGANIZATION_ERROR_CODES.NO_ACTIVE_ORGANIZATION });
3512
+ const member = await getOrgAdapter(ctx.context, options).findMemberByOrgId({
3513
+ userId: ctx.context.session.user.id,
3514
+ organizationId: activeOrganizationId
3515
+ });
3516
+ if (!member) throw new APIError("UNAUTHORIZED", { message: ORGANIZATION_ERROR_CODES.USER_IS_NOT_A_MEMBER_OF_THE_ORGANIZATION });
3517
+ const result = await hasPermission({
3518
+ role: member.role,
3519
+ options: options || {},
3520
+ permissions: ctx.body.permissions ?? ctx.body.permission,
3521
+ organizationId: activeOrganizationId
3522
+ }, ctx);
3523
+ return ctx.json({
3524
+ error: null,
3525
+ success: result
3526
+ });
3527
+ });
3528
+ };
3529
+ function organization(options) {
3530
+ let endpoints = {
3531
+ createOrganization: createOrganization(options),
3532
+ updateOrganization: updateOrganization(options),
3533
+ deleteOrganization: deleteOrganization(options),
3534
+ setActiveOrganization: setActiveOrganization(options),
3535
+ getFullOrganization: getFullOrganization(options),
3536
+ listOrganizations: listOrganizations(options),
3537
+ createInvitation: createInvitation(options),
3538
+ cancelInvitation: cancelInvitation(options),
3539
+ acceptInvitation: acceptInvitation(options),
3540
+ getInvitation: getInvitation(options),
3541
+ rejectInvitation: rejectInvitation(options),
3542
+ listInvitations: listInvitations(options),
3543
+ getActiveMember: getActiveMember(options),
3544
+ checkOrganizationSlug: checkOrganizationSlug(options),
3545
+ addMember: addMember(options),
3546
+ removeMember: removeMember(options),
3547
+ updateMemberRole: updateMemberRole(options),
3548
+ leaveOrganization: leaveOrganization(options),
3549
+ listUserInvitations: listUserInvitations(options),
3550
+ listMembers: listMembers(options),
3551
+ getActiveMemberRole: getActiveMemberRole(options)
3552
+ };
3553
+ const teamSupport = options?.teams?.enabled;
3554
+ const teamEndpoints = {
3555
+ createTeam: createTeam(options),
3556
+ listOrganizationTeams: listOrganizationTeams(options),
3557
+ removeTeam: removeTeam(options),
3558
+ updateTeam: updateTeam(options),
3559
+ setActiveTeam: setActiveTeam(options),
3560
+ listUserTeams: listUserTeams(options),
3561
+ listTeamMembers: listTeamMembers(options),
3562
+ addTeamMember: addTeamMember(options),
3563
+ removeTeamMember: removeTeamMember(options)
3564
+ };
3565
+ if (teamSupport) endpoints = {
3566
+ ...endpoints,
3567
+ ...teamEndpoints
3568
+ };
3569
+ const dynamicAccessControlEndpoints = {
3570
+ createOrgRole: createOrgRole(options),
3571
+ deleteOrgRole: deleteOrgRole(options),
3572
+ listOrgRoles: listOrgRoles(options),
3573
+ getOrgRole: getOrgRole(options),
3574
+ updateOrgRole: updateOrgRole(options)
3575
+ };
3576
+ if (options?.dynamicAccessControl?.enabled) endpoints = {
3577
+ ...endpoints,
3578
+ ...dynamicAccessControlEndpoints
3579
+ };
3580
+ const roles = {
3581
+ ...defaultRoles,
3582
+ ...options?.roles
3583
+ };
3584
+ const teamSchema$1 = teamSupport ? {
3585
+ team: {
3586
+ modelName: options?.schema?.team?.modelName,
3587
+ fields: {
3588
+ name: {
3589
+ type: "string",
3590
+ required: true,
3591
+ fieldName: options?.schema?.team?.fields?.name
3592
+ },
3593
+ organizationId: {
3594
+ type: "string",
3595
+ required: true,
3596
+ references: {
3597
+ model: "organization",
3598
+ field: "id"
3599
+ },
3600
+ fieldName: options?.schema?.team?.fields?.organizationId
3601
+ },
3602
+ createdAt: {
3603
+ type: "date",
3604
+ required: true,
3605
+ fieldName: options?.schema?.team?.fields?.createdAt
3606
+ },
3607
+ updatedAt: {
3608
+ type: "date",
3609
+ required: false,
3610
+ fieldName: options?.schema?.team?.fields?.updatedAt,
3611
+ onUpdate: () => /* @__PURE__ */ new Date()
3612
+ },
3613
+ ...options?.schema?.team?.additionalFields || {}
3614
+ }
3615
+ },
3616
+ teamMember: {
3617
+ modelName: options?.schema?.teamMember?.modelName,
3618
+ fields: {
3619
+ teamId: {
3620
+ type: "string",
3621
+ required: true,
3622
+ references: {
3623
+ model: "team",
3624
+ field: "id"
3625
+ },
3626
+ fieldName: options?.schema?.teamMember?.fields?.teamId
3627
+ },
3628
+ userId: {
3629
+ type: "string",
3630
+ required: true,
3631
+ references: {
3632
+ model: "user",
3633
+ field: "id"
3634
+ },
3635
+ fieldName: options?.schema?.teamMember?.fields?.userId
3636
+ },
3637
+ createdAt: {
3638
+ type: "date",
3639
+ required: false,
3640
+ fieldName: options?.schema?.teamMember?.fields?.createdAt
3641
+ }
3642
+ }
3643
+ }
3644
+ } : {};
3645
+ const organizationRoleSchema$1 = options?.dynamicAccessControl?.enabled ? { organizationRole: {
3646
+ fields: {
3647
+ organizationId: {
3648
+ type: "string",
3649
+ required: true,
3650
+ references: {
3651
+ model: "organization",
3652
+ field: "id"
3653
+ },
3654
+ fieldName: options?.schema?.organizationRole?.fields?.organizationId
3655
+ },
3656
+ role: {
3657
+ type: "string",
3658
+ required: true,
3659
+ fieldName: options?.schema?.organizationRole?.fields?.role
3660
+ },
3661
+ permission: {
3662
+ type: "string",
3663
+ required: true,
3664
+ fieldName: options?.schema?.organizationRole?.fields?.permission
3665
+ },
3666
+ createdAt: {
3667
+ type: "date",
3668
+ required: true,
3669
+ defaultValue: () => /* @__PURE__ */ new Date(),
3670
+ fieldName: options?.schema?.organizationRole?.fields?.createdAt
3671
+ },
3672
+ updatedAt: {
3673
+ type: "date",
3674
+ required: false,
3675
+ fieldName: options?.schema?.organizationRole?.fields?.updatedAt,
3676
+ onUpdate: () => /* @__PURE__ */ new Date()
3677
+ },
3678
+ ...options?.schema?.organizationRole?.additionalFields || {}
3679
+ },
3680
+ modelName: options?.schema?.organizationRole?.modelName
3681
+ } } : {};
3682
+ const schema = {
3683
+ organization: {
3684
+ modelName: options?.schema?.organization?.modelName,
3685
+ fields: {
3686
+ name: {
3687
+ type: "string",
3688
+ required: true,
3689
+ sortable: true,
3690
+ fieldName: options?.schema?.organization?.fields?.name
3691
+ },
3692
+ slug: {
3693
+ type: "string",
3694
+ required: true,
3695
+ unique: true,
3696
+ sortable: true,
3697
+ fieldName: options?.schema?.organization?.fields?.slug
3698
+ },
3699
+ logo: {
3700
+ type: "string",
3701
+ required: false,
3702
+ fieldName: options?.schema?.organization?.fields?.logo
3703
+ },
3704
+ createdAt: {
3705
+ type: "date",
3706
+ required: true,
3707
+ fieldName: options?.schema?.organization?.fields?.createdAt
3708
+ },
3709
+ metadata: {
3710
+ type: "string",
3711
+ required: false,
3712
+ fieldName: options?.schema?.organization?.fields?.metadata
3713
+ },
3714
+ ...options?.schema?.organization?.additionalFields || {}
3715
+ }
3716
+ },
3717
+ ...organizationRoleSchema$1,
3718
+ ...teamSchema$1,
3719
+ member: {
3720
+ modelName: options?.schema?.member?.modelName,
3721
+ fields: {
3722
+ organizationId: {
3723
+ type: "string",
3724
+ required: true,
3725
+ references: {
3726
+ model: "organization",
3727
+ field: "id"
3728
+ },
3729
+ fieldName: options?.schema?.member?.fields?.organizationId
3730
+ },
3731
+ userId: {
3732
+ type: "string",
3733
+ required: true,
3734
+ fieldName: options?.schema?.member?.fields?.userId,
3735
+ references: {
3736
+ model: "user",
3737
+ field: "id"
3738
+ }
3739
+ },
3740
+ role: {
3741
+ type: "string",
3742
+ required: true,
3743
+ sortable: true,
3744
+ defaultValue: "member",
3745
+ fieldName: options?.schema?.member?.fields?.role
3746
+ },
3747
+ createdAt: {
3748
+ type: "date",
3749
+ required: true,
3750
+ fieldName: options?.schema?.member?.fields?.createdAt
3751
+ },
3752
+ ...options?.schema?.member?.additionalFields || {}
3753
+ }
3754
+ },
3755
+ invitation: {
3756
+ modelName: options?.schema?.invitation?.modelName,
3757
+ fields: {
3758
+ organizationId: {
3759
+ type: "string",
3760
+ required: true,
3761
+ references: {
3762
+ model: "organization",
3763
+ field: "id"
3764
+ },
3765
+ fieldName: options?.schema?.invitation?.fields?.organizationId
3766
+ },
3767
+ email: {
3768
+ type: "string",
3769
+ required: true,
3770
+ sortable: true,
3771
+ fieldName: options?.schema?.invitation?.fields?.email
3772
+ },
3773
+ role: {
3774
+ type: "string",
3775
+ required: false,
3776
+ sortable: true,
3777
+ fieldName: options?.schema?.invitation?.fields?.role
3778
+ },
3779
+ ...teamSupport ? { teamId: {
3780
+ type: "string",
3781
+ required: false,
3782
+ sortable: true,
3783
+ fieldName: options?.schema?.invitation?.fields?.teamId
3784
+ } } : {},
3785
+ status: {
3786
+ type: "string",
3787
+ required: true,
3788
+ sortable: true,
3789
+ defaultValue: "pending",
3790
+ fieldName: options?.schema?.invitation?.fields?.status
3791
+ },
3792
+ expiresAt: {
3793
+ type: "date",
3794
+ required: true,
3795
+ fieldName: options?.schema?.invitation?.fields?.expiresAt
3796
+ },
3797
+ createdAt: {
3798
+ type: "date",
3799
+ required: true,
3800
+ fieldName: options?.schema?.invitation?.fields?.createdAt,
3801
+ defaultValue: () => /* @__PURE__ */ new Date()
3802
+ },
3803
+ inviterId: {
3804
+ type: "string",
3805
+ references: {
3806
+ model: "user",
3807
+ field: "id"
3808
+ },
3809
+ fieldName: options?.schema?.invitation?.fields?.inviterId,
3810
+ required: true
3811
+ },
3812
+ ...options?.schema?.invitation?.additionalFields || {}
3813
+ }
3814
+ }
3815
+ };
3816
+ return {
3817
+ id: "organization",
3818
+ endpoints: {
3819
+ ...shimContext(endpoints, {
3820
+ orgOptions: options || {},
3821
+ roles,
3822
+ getSession: async (context) => {
3823
+ return await getSessionFromCtx(context);
3824
+ }
3825
+ }),
3826
+ hasPermission: createHasPermission(options)
3827
+ },
3828
+ schema: {
3829
+ ...schema,
3830
+ session: { fields: {
3831
+ activeOrganizationId: {
3832
+ type: "string",
3833
+ required: false,
3834
+ fieldName: options?.schema?.session?.fields?.activeOrganizationId
3835
+ },
3836
+ ...teamSupport ? { activeTeamId: {
3837
+ type: "string",
3838
+ required: false,
3839
+ fieldName: options?.schema?.session?.fields?.activeTeamId
3840
+ } } : {}
3841
+ } }
3842
+ },
3843
+ $Infer: {
3844
+ Organization: {},
3845
+ Invitation: {},
3846
+ Member: {},
3847
+ Team: teamSupport ? {} : {},
3848
+ TeamMember: teamSupport ? {} : {},
3849
+ ActiveOrganization: {}
3850
+ },
3851
+ $ERROR_CODES: ORGANIZATION_ERROR_CODES,
3852
+ options
3853
+ };
3854
+ }
3855
+
3856
+ //#endregion
3857
+ export { parseRoles as n, organization as t };