@rpcbase/auth 0.197.0 → 0.199.0

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 (63) hide show
  1. package/dist/components/AppleSignInButton/index.d.ts +1 -1
  2. package/dist/components/AppleSignInButton/index.d.ts.map +1 -1
  3. package/dist/components/AuthLayout/index.d.ts +1 -1
  4. package/dist/components/AuthLayout/index.d.ts.map +1 -1
  5. package/dist/components/EmailInput/index.d.ts +1 -1
  6. package/dist/components/EmailInput/index.d.ts.map +1 -1
  7. package/dist/components/PasswordInput/index.d.ts +1 -1
  8. package/dist/components/PasswordInput/index.d.ts.map +1 -1
  9. package/dist/components/RememberMeCheckbox/index.d.ts +1 -1
  10. package/dist/components/RememberMeCheckbox/index.d.ts.map +1 -1
  11. package/dist/components/ResendCodeButton/index.d.ts +1 -1
  12. package/dist/components/ResendCodeButton/index.d.ts.map +1 -1
  13. package/dist/components/SignInForm/index.d.ts +1 -1
  14. package/dist/components/SignInForm/index.d.ts.map +1 -1
  15. package/dist/components/SignUpForm/index.d.ts +1 -1
  16. package/dist/components/SignUpForm/index.d.ts.map +1 -1
  17. package/dist/{handler-DAKI9QOQ.js → handler-1Jy7G8dM.js} +2 -2
  18. package/dist/handler-1Jy7G8dM.js.map +1 -0
  19. package/dist/{handler-Dw3o3smk.js → handler-B1Z9YpER.js} +3 -3
  20. package/dist/handler-B1Z9YpER.js.map +1 -0
  21. package/dist/{handler-W_XZ0lnx.js → handler-BgjYCWF4.js} +2 -2
  22. package/dist/handler-BgjYCWF4.js.map +1 -0
  23. package/dist/{handler-DetFi4-9.js → handler-BkZLC8Bg.js} +3 -3
  24. package/dist/handler-BkZLC8Bg.js.map +1 -0
  25. package/dist/{handler-J2FOxq-2.js → handler-CF3fSh8e.js} +2 -2
  26. package/dist/handler-CF3fSh8e.js.map +1 -0
  27. package/dist/{handler-DH9FPTNh.js → handler-D4ui5jV4.js} +2 -2
  28. package/dist/handler-D4ui5jV4.js.map +1 -0
  29. package/dist/{handler-DQvdRpG2.js → handler-DBbjgU-f.js} +2 -2
  30. package/dist/handler-DBbjgU-f.js.map +1 -0
  31. package/dist/{handler-BY6DP3QP.js → handler-Dbw6BOmj.js} +3 -3
  32. package/dist/handler-Dbw6BOmj.js.map +1 -0
  33. package/dist/{handler-DoyR_l2O.js → handler-DgIcxthg.js} +2 -2
  34. package/dist/handler-DgIcxthg.js.map +1 -0
  35. package/dist/{handler-DAfIloZR.js → handler-iT2eSHpE.js} +3 -3
  36. package/dist/handler-iT2eSHpE.js.map +1 -0
  37. package/dist/index.js +64 -195
  38. package/dist/index.js.map +1 -1
  39. package/dist/middleware-BT3Uput1.js.map +1 -1
  40. package/dist/oauth/index.js +2 -2
  41. package/dist/oauth/index.js.map +1 -1
  42. package/dist/routes.js +10 -10
  43. package/dist/routes.js.map +1 -1
  44. package/dist/{schemas-BgOpQqUv.js → schemas-CMgO_xn9.js} +29 -22
  45. package/dist/{schemas-BgOpQqUv.js.map → schemas-CMgO_xn9.js.map} +1 -1
  46. package/dist/session-BQ06Yo3C.js.map +1 -1
  47. package/dist/{sign-in-BkhQovKN.js → sign-in-DYq3bJeH.js} +2 -2
  48. package/dist/sign-in-DYq3bJeH.js.map +1 -0
  49. package/dist/{sign-up-Di48rzbG.js → sign-up-CYGadNUe.js} +2 -2
  50. package/dist/sign-up-CYGadNUe.js.map +1 -0
  51. package/package.json +1 -1
  52. package/dist/handler-BY6DP3QP.js.map +0 -1
  53. package/dist/handler-DAKI9QOQ.js.map +0 -1
  54. package/dist/handler-DAfIloZR.js.map +0 -1
  55. package/dist/handler-DH9FPTNh.js.map +0 -1
  56. package/dist/handler-DQvdRpG2.js.map +0 -1
  57. package/dist/handler-DetFi4-9.js.map +0 -1
  58. package/dist/handler-DoyR_l2O.js.map +0 -1
  59. package/dist/handler-Dw3o3smk.js.map +0 -1
  60. package/dist/handler-J2FOxq-2.js.map +0 -1
  61. package/dist/handler-W_XZ0lnx.js.map +0 -1
  62. package/dist/sign-in-BkhQovKN.js.map +0 -1
  63. package/dist/sign-up-Di48rzbG.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  export declare const AppleSignInButton: ({ onPress, className, }: {
2
2
  onPress: () => void;
3
3
  className?: string;
4
- }) => import("react/jsx-runtime").JSX.Element;
4
+ }) => import("react").JSX.Element;
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/AppleSignInButton/index.tsx"],"names":[],"mappings":"AAGA,eAAO,MAAM,iBAAiB,GAAI,yBAG/B;IACD,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,4CA2BA,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/AppleSignInButton/index.tsx"],"names":[],"mappings":"AAGA,eAAO,MAAM,iBAAiB,GAAI,yBAG/B;IACD,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,gCA2BA,CAAA"}
@@ -2,5 +2,5 @@ import * as React from "react";
2
2
  export declare const AuthLayout: ({ sidePanel, children, }: {
3
3
  sidePanel: React.ReactElement | null;
4
4
  children: React.ReactNode;
5
- }) => import("react/jsx-runtime").JSX.Element;
5
+ }) => React.JSX.Element;
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/AuthLayout/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAqB9B,eAAO,MAAM,UAAU,GAAI,0BAGxB;IACD,SAAS,EAAE,KAAK,CAAC,YAAY,GAAG,IAAI,CAAA;IACpC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B,4CAyBA,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/AuthLayout/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAqB9B,eAAO,MAAM,UAAU,GAAI,0BAGxB;IACD,SAAS,EAAE,KAAK,CAAC,YAAY,GAAG,IAAI,CAAA;IACpC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B,sBAyBA,CAAA"}
@@ -2,5 +2,5 @@ export declare const EmailInput: ({ id, className, placeholder, }: {
2
2
  id: string;
3
3
  className?: string;
4
4
  placeholder?: string;
5
- }) => import("react/jsx-runtime").JSX.Element;
5
+ }) => import("react").JSX.Element;
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/EmailInput/index.tsx"],"names":[],"mappings":"AAIA,eAAO,MAAM,UAAU,GAAI,iCAIxB;IACD,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,4CA2BA,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/EmailInput/index.tsx"],"names":[],"mappings":"AAIA,eAAO,MAAM,UAAU,GAAI,iCAIxB;IACD,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,gCA2BA,CAAA"}
@@ -5,6 +5,6 @@ type PasswordInputProps = {
5
5
  placeholder?: string;
6
6
  autoComplete?: string;
7
7
  };
8
- export declare const PasswordInput: ({ id, name, className, placeholder, autoComplete, }: PasswordInputProps) => import("react/jsx-runtime").JSX.Element;
8
+ export declare const PasswordInput: ({ id, name, className, placeholder, autoComplete, }: PasswordInputProps) => import("react").JSX.Element;
9
9
  export {};
10
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/PasswordInput/index.tsx"],"names":[],"mappings":"AAMA,KAAK,kBAAkB,GAAG;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,eAAO,MAAM,aAAa,GAAI,qDAM3B,kBAAkB,4CA2CpB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/PasswordInput/index.tsx"],"names":[],"mappings":"AAMA,KAAK,kBAAkB,GAAG;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,eAAO,MAAM,aAAa,GAAI,qDAM3B,kBAAkB,gCA2CpB,CAAA"}
@@ -2,5 +2,5 @@ import { ElementType } from 'react';
2
2
  export declare const RememberMeCheckbox: ({ label, as: Component }: {
3
3
  label: string;
4
4
  as?: ElementType;
5
- }) => import("react/jsx-runtime").JSX.Element;
5
+ }) => import("react").JSX.Element;
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/RememberMeCheckbox/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AAIxC,eAAO,MAAM,kBAAkB,GAAI,0BAGhC;IACD,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,WAAW,CAAA;CACjB,4CAiBA,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/RememberMeCheckbox/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AAIxC,eAAO,MAAM,kBAAkB,GAAI,0BAGhC;IACD,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,WAAW,CAAA;CACjB,gCAiBA,CAAA"}
@@ -10,5 +10,5 @@ export declare const ResendCodeButton: ({ seconds, onResend, className, disabled
10
10
  onResend?: () => Promise<void> | void;
11
11
  className?: string;
12
12
  disabled?: boolean;
13
- }) => import("react/jsx-runtime").JSX.Element;
13
+ }) => import("react").JSX.Element;
14
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ResendCodeButton/index.tsx"],"names":[],"mappings":"AAIA,eAAO,MAAM,kBAAkB,GAAI,gBAAY,EAAE,+BAA4B;;;;;4BAoB5C,MAAM;CAatC,CAAA;AAGD,eAAO,MAAM,gBAAgB,GAAI,6CAK9B;IACD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACrC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,4CA8CA,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ResendCodeButton/index.tsx"],"names":[],"mappings":"AAIA,eAAO,MAAM,kBAAkB,GAAI,gBAAY,EAAE,+BAA4B;;;;;4BAoB5C,MAAM;CAatC,CAAA;AAGD,eAAO,MAAM,gBAAgB,GAAI,6CAK9B;IACD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACrC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,gCA8CA,CAAA"}
@@ -2,5 +2,5 @@ import { ReactNode } from 'react';
2
2
  export declare const SignInForm: ({ children, className }: {
3
3
  children: ReactNode;
4
4
  className?: string;
5
- }) => import("react/jsx-runtime").JSX.Element;
5
+ }) => import("react").JSX.Element;
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/SignInForm/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAYjC,eAAO,MAAM,UAAU,GAAI,yBAGxB;IACD,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,4CAwDA,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/SignInForm/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAYjC,eAAO,MAAM,UAAU,GAAI,yBAGxB;IACD,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,gCAwDA,CAAA"}
@@ -3,5 +3,5 @@ export declare const SignUpForm: ({ children, className, otpNextPath }: {
3
3
  children: ReactNode;
4
4
  className?: string;
5
5
  otpNextPath?: string;
6
- }) => import("react/jsx-runtime").JSX.Element;
6
+ }) => import("react").JSX.Element;
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/SignUpForm/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAW,MAAM,OAAO,CAAA;AAYzC,eAAO,MAAM,UAAU,GAAI,sCAIxB;IACD,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,4CAwEA,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/SignUpForm/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAW,MAAM,OAAO,CAAA;AAYzC,eAAO,MAAM,UAAU,GAAI,sCAIxB;IACD,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,gCAwEA,CAAA"}
@@ -1,4 +1,4 @@
1
- import { a as string, i as object, n as boolean } from "./schemas-BgOpQqUv.js";
1
+ import { a as string, i as object, n as boolean } from "./schemas-CMgO_xn9.js";
2
2
  import { n as completeAuthSignIn } from "./session-BQ06Yo3C.js";
3
3
  import { models } from "@rpcbase/db";
4
4
  //#region src/api/verify-otp/index.ts
@@ -89,4 +89,4 @@ var handler_default = (api) => {
89
89
  //#endregion
90
90
  export { handler_default as default };
91
91
 
92
- //# sourceMappingURL=handler-DAKI9QOQ.js.map
92
+ //# sourceMappingURL=handler-1Jy7G8dM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler-1Jy7G8dM.js","names":[],"sources":["../src/api/verify-otp/index.ts","../src/api/verify-otp/handler.ts"],"sourcesContent":["import { z } from \"zod\"\n\n\nexport const ROUTE = \"/api/rb/auth/verify-otp\"\n\nexport const requestSchema = z.object({\n email: z.string().email(),\n code: z.string().length(6, \"Code must be 6 digits\"),\n rememberMe: z.boolean().default(true),\n})\n\nexport type RequestPayload = z.infer<typeof requestSchema>\n\nexport const responseSchema = z.object({\n success: z.boolean(),\n error: z.string().optional(),\n userId: z.string().optional(),\n tenantId: z.string().optional(),\n})\n\nexport type ResponsePayload = z.infer<typeof responseSchema>\n","import { Api, ApiHandler, Ctx } from \"@rpcbase/api\"\nimport { models } from \"@rpcbase/db\"\n\nimport { completeAuthSignIn } from \"../../session\"\nimport type { AuthSessionUser } from \"../../types\"\n\nimport * as VerifyOtp from \"./index\"\n\n\nconst verifyOtp: ApiHandler<VerifyOtp.RequestPayload, VerifyOtp.ResponsePayload, AuthSessionUser> = async (\n payload,\n ctx: Ctx<AuthSessionUser>\n): Promise<VerifyOtp.ResponsePayload> => {\n const User = await models.getGlobal(\"RBUser\", ctx)\n\n const parsed = VerifyOtp.requestSchema.safeParse(payload)\n\n if (!parsed.success) {\n ctx.res.status(400)\n return { success: false, error: \"invalid_payload\" }\n }\n\n const { email, code } = parsed.data\n\n const user = await User.findOne({ email }, { emailVerificationCode: 1, emailVerificationExpiresAt: 1, tenants: 1, tenantRoles: 1 })\n\n if (!user) {\n ctx.res.status(404)\n return { success: false, error: \"user_not_found\" }\n }\n\n const storedCode = user.emailVerificationCode\n const expiresAt = user.emailVerificationExpiresAt\n\n const isExpired = expiresAt instanceof Date && expiresAt.getTime() < Date.now()\n if (!storedCode || storedCode !== code || isExpired) {\n ctx.res.status(400)\n return { success: false, error: \"invalid_code\" }\n }\n\n user.emailVerificationCode = undefined\n user.emailVerificationExpiresAt = undefined\n await user.save()\n\n const signedInTenants = (user.tenants || []).map(String)\n const defaultTenantId = signedInTenants[0]\n if (!defaultTenantId) {\n ctx.res.status(500)\n return { success: false, error: \"tenant_unavailable\" }\n }\n const tenantId = defaultTenantId\n const tenantRolesMap = user.get(\"tenantRoles\") as Map<string, string[]> | undefined\n const tenantRoles = tenantRolesMap ? Object.fromEntries(tenantRolesMap.entries()) : undefined\n\n if (!completeAuthSignIn(ctx, {\n userId: user._id.toString(),\n currentTenantId: tenantId,\n signedInTenants: signedInTenants.length ? signedInTenants : [tenantId],\n tenantRoles,\n })) {\n ctx.res.status(500)\n return { success: false, error: \"session_unavailable\" }\n }\n\n return { success: true, userId: user._id.toString(), tenantId }\n}\n\nexport default (api: Api<AuthSessionUser>) => {\n api.post(VerifyOtp.ROUTE, verifyOtp)\n}\n"],"mappings":";;;;AAGA,IAAa,QAAQ;AAErB,IAAa,gBAAgB,OAAS;CACpC,OAAO,OAAS,CAAC,CAAC,MAAM;CACxB,MAAM,OAAS,CAAC,CAAC,OAAO,GAAG,uBAAuB;CAClD,YAAY,QAAU,CAAC,CAAC,QAAQ,IAAI;AACtC,CAAC;AAI6B,OAAS;CACrC,SAAS,QAAU;CACnB,OAAO,OAAS,CAAC,CAAC,SAAS;CAC3B,QAAQ,OAAS,CAAC,CAAC,SAAS;CAC5B,UAAU,OAAS,CAAC,CAAC,SAAS;AAChC,CAAC;;;ACTD,IAAM,YAA8F,OAClG,SACA,QACuC;CACvC,MAAM,OAAO,MAAM,OAAO,UAAU,UAAU,GAAG;CAEjD,MAAM,SAAA,cAAiC,UAAU,OAAO;CAExD,IAAI,CAAC,OAAO,SAAS;EACnB,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAkB;CACpD;CAEA,MAAM,EAAE,OAAO,SAAS,OAAO;CAE/B,MAAM,OAAO,MAAM,KAAK,QAAQ,EAAE,MAAM,GAAG;EAAE,uBAAuB;EAAG,4BAA4B;EAAG,SAAS;EAAG,aAAa;CAAE,CAAC;CAElI,IAAI,CAAC,MAAM;EACT,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAiB;CACnD;CAEA,MAAM,aAAa,KAAK;CACxB,MAAM,YAAY,KAAK;CAEvB,MAAM,YAAY,qBAAqB,QAAQ,UAAU,QAAQ,IAAI,KAAK,IAAI;CAC9E,IAAI,CAAC,cAAc,eAAe,QAAQ,WAAW;EACnD,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAe;CACjD;CAEA,KAAK,wBAAwB,KAAA;CAC7B,KAAK,6BAA6B,KAAA;CAClC,MAAM,KAAK,KAAK;CAEhB,MAAM,mBAAmB,KAAK,WAAW,CAAA,EAAA,CAAI,IAAI,MAAM;CACvD,MAAM,kBAAkB,gBAAgB;CACxC,IAAI,CAAC,iBAAiB;EACpB,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAqB;CACvD;CACA,MAAM,WAAW;CACjB,MAAM,iBAAiB,KAAK,IAAI,aAAa;CAC7C,MAAM,cAAc,iBAAiB,OAAO,YAAY,eAAe,QAAQ,CAAC,IAAI,KAAA;CAEpF,IAAI,CAAC,mBAAmB,KAAK;EAC3B,QAAQ,KAAK,IAAI,SAAS;EAC1B,iBAAiB;EACjB,iBAAiB,gBAAgB,SAAS,kBAAkB,CAAC,QAAQ;EACrE;CACF,CAAC,GAAG;EACF,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAsB;CACxD;CAEA,OAAO;EAAE,SAAS;EAAM,QAAQ,KAAK,IAAI,SAAS;EAAG;CAAS;AAChE;AAEA,IAAA,mBAAgB,QAA8B;CAC5C,IAAI,KAAK,OAAiB,SAAS;AACrC"}
@@ -1,4 +1,4 @@
1
- import { a as string, i as object, n as boolean } from "./schemas-BgOpQqUv.js";
1
+ import { a as string, i as object, n as boolean } from "./schemas-CMgO_xn9.js";
2
2
  import { t as email_validation_exports } from "./email-validation/index.js";
3
3
  import crypto from "crypto";
4
4
  import { models } from "@rpcbase/db";
@@ -33,7 +33,7 @@ var resendOtp = async (payload, ctx) => {
33
33
  };
34
34
  }
35
35
  const emailVerificationCode = crypto.randomInt(0, 1e6).toString().padStart(6, "0");
36
- const emailVerificationExpiresAt = new Date(Date.now() + 600 * 1e3);
36
+ const emailVerificationExpiresAt = new Date(Date.now() + 6e5);
37
37
  user.emailVerificationCode = emailVerificationCode;
38
38
  user.emailVerificationExpiresAt = emailVerificationExpiresAt;
39
39
  await user.save();
@@ -74,4 +74,4 @@ var handler_default = (api) => {
74
74
  //#endregion
75
75
  export { handler_default as default, resendOtp };
76
76
 
77
- //# sourceMappingURL=handler-Dw3o3smk.js.map
77
+ //# sourceMappingURL=handler-B1Z9YpER.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler-B1Z9YpER.js","names":[],"sources":["../src/api/resend-otp/index.ts","../src/api/resend-otp/handler.ts"],"sourcesContent":["import { z } from \"zod\"\n\n\nexport const ROUTE = \"/api/rb/auth/resend-otp\"\n\nexport const requestSchema = z.object({\n email: z.string().email(),\n})\n\nexport type RequestPayload = z.infer<typeof requestSchema>\n\nexport const responseSchema = z.object({\n success: z.boolean(),\n error: z.string().optional(),\n})\n\nexport type ResponsePayload = z.infer<typeof responseSchema>\n\n","import crypto from \"crypto\"\n\nimport { Api, ApiHandler, Ctx } from \"@rpcbase/api\"\nimport { models } from \"@rpcbase/db\"\nimport { sendEmail } from \"@rpcbase/server\"\n\nimport { isEmailAddressValid } from \"../../email-validation\"\nimport type { AuthSessionUser } from \"../../types\"\n\nimport * as ResendOtp from \"./index\"\n\n\nexport const resendOtp: ApiHandler<ResendOtp.RequestPayload, ResendOtp.ResponsePayload, AuthSessionUser> = async (\n payload,\n ctx: Ctx<AuthSessionUser>\n): Promise<ResendOtp.ResponsePayload> => {\n const parsed = ResendOtp.requestSchema.safeParse(payload)\n\n if (!parsed.success) {\n ctx.res.status(400)\n return { success: false, error: \"invalid_payload\" }\n }\n\n const { email } = parsed.data\n\n if (!await isEmailAddressValid(email)) {\n return { success: true }\n }\n\n const User = await models.getGlobal(\"RBUser\", ctx)\n const user = await User.findOne({ email })\n\n if (!user) {\n // TODO(auth): avoid account enumeration (return a generic success response even when the user doesn't exist)\n ctx.res.status(404)\n return { success: false, error: \"user_not_found\" }\n }\n\n // TODO(auth): add server-side throttling / rate limiting for resend-otp\n const emailVerificationCode = crypto.randomInt(0, 1_000_000).toString().padStart(6, \"0\")\n const emailVerificationExpiresAt = new Date(Date.now() + 10 * 60 * 1000)\n\n user.emailVerificationCode = emailVerificationCode\n user.emailVerificationExpiresAt = emailVerificationExpiresAt\n await user.save()\n\n try {\n await sendEmail({\n to: email,\n subject: `Your verification code: ${emailVerificationCode}`,\n html: `\n <p>Your verification code is <strong>${emailVerificationCode}</strong>. It expires in 10 minutes.</p>\n <p>If you didn't request this, you can ignore this message.</p>\n `,\n text: `Your verification code is ${emailVerificationCode}. It expires in 10 minutes. If you didn't request this, you can ignore this message.`,\n })\n } catch (err) {\n console.error(\"failed to resend otp email\", err)\n\n try {\n await User.updateOne(\n { _id: user._id, emailVerificationCode },\n {\n $unset: {\n emailVerificationCode: \"\",\n emailVerificationExpiresAt: \"\",\n },\n },\n )\n } catch (releaseErr) {\n console.error(\"failed to clear unsent otp\", releaseErr)\n }\n\n ctx.res.status(500)\n return { success: false, error: \"email_delivery_failed\" }\n }\n\n return { success: true }\n}\n\nexport default (api: Api<AuthSessionUser>) => {\n api.post(ResendOtp.ROUTE, resendOtp)\n}\n"],"mappings":";;;;;;AAGA,IAAa,QAAQ;AAErB,IAAa,gBAAgB,OAAS,EACpC,OAAO,OAAS,CAAC,CAAC,MAAM,EAC1B,CAAC;AAI6B,OAAS;CACrC,SAAS,QAAU;CACnB,OAAO,OAAS,CAAC,CAAC,SAAS;AAC7B,CAAC;;;ACFD,IAAa,YAA8F,OACzG,SACA,QACuC;CACvC,MAAM,SAAA,cAAiC,UAAU,OAAO;CAExD,IAAI,CAAC,OAAO,SAAS;EACnB,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAkB;CACpD;CAEA,MAAM,EAAE,UAAU,OAAO;CAEzB,IAAI,CAAC,OAAA,GAAM,yBAAA,oBAAA,CAAoB,KAAK,GAClC,OAAO,EAAE,SAAS,KAAK;CAGzB,MAAM,OAAO,MAAM,OAAO,UAAU,UAAU,GAAG;CACjD,MAAM,OAAO,MAAM,KAAK,QAAQ,EAAE,MAAM,CAAC;CAEzC,IAAI,CAAC,MAAM;EAET,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAiB;CACnD;CAGA,MAAM,wBAAwB,OAAO,UAAU,GAAG,GAAS,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,GAAG,GAAG;CACvF,MAAM,6BAA6B,IAAI,KAAK,KAAK,IAAI,IAAI,GAAc;CAEvE,KAAK,wBAAwB;CAC7B,KAAK,6BAA6B;CAClC,MAAM,KAAK,KAAK;CAEhB,IAAI;EACF,MAAM,UAAU;GACd,IAAI;GACJ,SAAS,2BAA2B;GACpC,MAAM;+CACmC,sBAAqB;;;GAG9D,MAAM,6BAA6B,sBAAqB;EAC1D,CAAC;CACH,SAAS,KAAK;EACZ,QAAQ,MAAM,8BAA8B,GAAG;EAE/C,IAAI;GACF,MAAM,KAAK,UACT;IAAE,KAAK,KAAK;IAAK;GAAsB,GACvC,EACE,QAAQ;IACN,uBAAuB;IACvB,4BAA4B;GAC9B,EACF,CACF;EACF,SAAS,YAAY;GACnB,QAAQ,MAAM,8BAA8B,UAAU;EACxD;EAEA,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAwB;CAC1D;CAEA,OAAO,EAAE,SAAS,KAAK;AACzB;AAEA,IAAA,mBAAgB,QAA8B;CAC5C,IAAI,KAAK,OAAiB,SAAS;AACrC"}
@@ -1,4 +1,4 @@
1
- import { a as string, i as object, t as array } from "./schemas-BgOpQqUv.js";
1
+ import { a as string, i as object, t as array } from "./schemas-CMgO_xn9.js";
2
2
  import { r as restrictSessionMiddleware } from "./middleware-BT3Uput1.js";
3
3
  import { models } from "@rpcbase/db";
4
4
  //#region src/api/me/index.ts
@@ -67,4 +67,4 @@ var handler_default = (api) => {
67
67
  //#endregion
68
68
  export { handler_default as default };
69
69
 
70
- //# sourceMappingURL=handler-W_XZ0lnx.js.map
70
+ //# sourceMappingURL=handler-BgjYCWF4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler-BgjYCWF4.js","names":[],"sources":["../src/api/me/index.ts","../src/api/me/handler.ts"],"sourcesContent":["import { z } from \"zod\"\n\n\nexport const ROUTE = \"/api/rb/auth/me\"\n\nexport const requestSchema = z.object({})\nexport type RequestPayload = z.infer<typeof requestSchema>\n\nexport const responseSchema = z.object({\n id: z.string().optional(),\n email: z.string().email().optional(),\n phone: z.string().optional(),\n name: z.string().optional(),\n tenants: z.array(z.string()).default([]),\n currentTenantId: z.string().optional(),\n signedInTenants: z.array(z.string()).default([]).optional(),\n error: z.string().optional(),\n})\n\nexport type ResponsePayload = z.infer<typeof responseSchema>\n","import { Api, ApiHandler, Ctx } from \"@rpcbase/api\"\nimport { models } from \"@rpcbase/db\"\n\nimport type { AuthSessionUser } from \"../../types\"\nimport { restrictSessionMiddleware } from \"../../middleware\"\n\nimport * as Me from \"./index\"\n\n\nconst me: ApiHandler<Me.RequestPayload, Me.ResponsePayload, AuthSessionUser> = async(\n _payload: Me.RequestPayload,\n ctx: Ctx<AuthSessionUser>\n): Promise<Me.ResponsePayload> => {\n const sessionUser = ctx.req.session?.user\n\n if (!sessionUser?.id) {\n ctx.res.status(401)\n return {\n id: \"\",\n currentTenantId: \"\",\n signedInTenants: [],\n tenants: [],\n error: \"not_authenticated\",\n } as unknown as Me.ResponsePayload\n }\n\n const User = await models.getGlobal(\"RBUser\", ctx)\n const user = await User.findById(sessionUser.id)\n\n if (!user) {\n ctx.res.status(404)\n return {\n id: \"\",\n currentTenantId: \"\",\n signedInTenants: [],\n tenants: [],\n error: \"user_not_found\",\n } as unknown as Me.ResponsePayload\n }\n\n const tenantId = typeof sessionUser.currentTenantId === \"string\" ? sessionUser.currentTenantId.trim() : \"\"\n if (!tenantId) {\n ctx.res.status(500)\n return {\n id: \"\",\n currentTenantId: \"\",\n signedInTenants: [],\n tenants: [],\n error: \"tenant_missing\",\n } as unknown as Me.ResponsePayload\n }\n\n return {\n id: user._id.toString(),\n email: user.email,\n phone: user.get(\"phone\") as string | undefined,\n name: user.name,\n tenants: (user.tenants || []).map(String),\n currentTenantId: tenantId,\n signedInTenants: sessionUser.signedInTenants || [],\n }\n}\n\nexport default (api: Api<AuthSessionUser>) => {\n api.use(Me.ROUTE, restrictSessionMiddleware)\n api.get(Me.ROUTE, me)\n}\n"],"mappings":";;;;AAGA,IAAa,QAAQ;AAEQ,OAAS,CAAC,CAAC;AAGV,OAAS;CACrC,IAAI,OAAS,CAAC,CAAC,SAAS;CACxB,OAAO,OAAS,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS;CACnC,OAAO,OAAS,CAAC,CAAC,SAAS;CAC3B,MAAM,OAAS,CAAC,CAAC,SAAS;CAC1B,SAAS,MAAQ,OAAS,CAAC,CAAC,CAAC,QAAQ,CAAA,CAAE;CACvC,iBAAiB,OAAS,CAAC,CAAC,SAAS;CACrC,iBAAiB,MAAQ,OAAS,CAAC,CAAC,CAAC,QAAQ,CAAA,CAAE,CAAC,CAAC,SAAS;CAC1D,OAAO,OAAS,CAAC,CAAC,SAAS;AAC7B,CAAC;;;ACRD,IAAM,KAAyE,OAC7E,UACA,QACgC;CAChC,MAAM,cAAc,IAAI,IAAI,SAAS;CAErC,IAAI,CAAC,aAAa,IAAI;EACpB,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GACL,IAAI;GACJ,iBAAiB;GACjB,iBAAiB,CAAA;GACjB,SAAS,CAAA;GACT,OAAO;EACT;CACF;CAGA,MAAM,OAAO,OAAM,MADA,OAAO,UAAU,UAAU,GAAG,EAAA,CACzB,SAAS,YAAY,EAAE;CAE/C,IAAI,CAAC,MAAM;EACT,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GACL,IAAI;GACJ,iBAAiB;GACjB,iBAAiB,CAAA;GACjB,SAAS,CAAA;GACT,OAAO;EACT;CACF;CAEA,MAAM,WAAW,OAAO,YAAY,oBAAoB,WAAW,YAAY,gBAAgB,KAAK,IAAI;CACxG,IAAI,CAAC,UAAU;EACb,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GACL,IAAI;GACJ,iBAAiB;GACjB,iBAAiB,CAAA;GACjB,SAAS,CAAA;GACT,OAAO;EACT;CACF;CAEA,OAAO;EACL,IAAI,KAAK,IAAI,SAAS;EACtB,OAAO,KAAK;EACZ,OAAO,KAAK,IAAI,OAAO;EACvB,MAAM,KAAK;EACX,UAAU,KAAK,WAAW,CAAA,EAAA,CAAI,IAAI,MAAM;EACxC,iBAAiB;EACjB,iBAAiB,YAAY,mBAAmB,CAAA;CAClD;AACF;AAEA,IAAA,mBAAgB,QAA8B;CAC5C,IAAI,IAAI,OAAU,yBAAyB;CAC3C,IAAI,IAAI,OAAU,EAAE;AACtB"}
@@ -1,4 +1,4 @@
1
- import { n as requestSchema, t as ROUTE } from "./sign-up-Di48rzbG.js";
1
+ import { n as requestSchema, t as ROUTE } from "./sign-up-CYGadNUe.js";
2
2
  import { t as email_validation_exports } from "./email-validation/index.js";
3
3
  import crypto from "crypto";
4
4
  import { createProvisionedTenant, models } from "@rpcbase/db";
@@ -28,7 +28,7 @@ var signUp = async (payload, ctx) => {
28
28
  const hashedPassword = await hashPasswordForStorage(password);
29
29
  const tenantId = crypto.randomUUID();
30
30
  const emailVerificationCode = crypto.randomInt(0, 1e6).toString().padStart(6, "0");
31
- const emailVerificationExpiresAt = new Date(Date.now() + 600 * 1e3);
31
+ const emailVerificationExpiresAt = new Date(Date.now() + 6e5);
32
32
  const user = new User({
33
33
  email,
34
34
  password: hashedPassword,
@@ -89,4 +89,4 @@ var handler_default = (api) => {
89
89
  //#endregion
90
90
  export { handler_default as default, signUp };
91
91
 
92
- //# sourceMappingURL=handler-DetFi4-9.js.map
92
+ //# sourceMappingURL=handler-BkZLC8Bg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler-BkZLC8Bg.js","names":[],"sources":["../src/api/sign-up/handler.ts"],"sourcesContent":["import crypto from \"crypto\"\n\nimport { Api, Ctx, ApiHandler } from \"@rpcbase/api\"\nimport { createProvisionedTenant, models } from \"@rpcbase/db\"\nimport { hashPasswordForStorage, sendEmail } from \"@rpcbase/server\"\n\nimport { isEmailAddressValid } from \"../../email-validation\"\nimport type { AuthSessionUser } from \"../../types\"\n\nimport * as SignUp from \"./index\"\n\n\nexport const signUp: ApiHandler<SignUp.RequestPayload, SignUp.ResponsePayload, AuthSessionUser> = async(\n payload,\n ctx: Ctx<AuthSessionUser>\n): Promise<SignUp.ResponsePayload> => {\n const parsed = SignUp.requestSchema.safeParse(payload)\n\n if (!parsed.success) {\n ctx.res.status(400)\n return { success: false, error: \"invalid_payload\" }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { email, password, rememberMe: _rememberMe } = parsed.data\n\n if (!await isEmailAddressValid(email)) {\n return { success: true }\n }\n\n const User = await models.getGlobal(\"RBUser\", ctx)\n const Tenant = await models.getGlobal(\"RBTenant\", ctx)\n\n const existingUser = await User.findOne({ email })\n\n if (existingUser) {\n console.log(\"user with email already exists\", email)\n // For security, we don't want to reveal if an email is registered.\n // But for this implementation, we'll make it simple.\n ctx.res.status(409)\n return { success: false, error: \"user_exists\" }\n }\n\n const hashedPassword = await hashPasswordForStorage(password)\n\n const tenantId = crypto.randomUUID()\n\n const emailVerificationCode = crypto.randomInt(0, 1_000_000).toString().padStart(6, \"0\")\n const emailVerificationExpiresAt = new Date(Date.now() + 10 * 60 * 1000)\n\n const user = new User({\n email,\n password: hashedPassword,\n tenants: [tenantId],\n tenantRoles: {\n [tenantId]: [\"owner\"],\n },\n emailVerificationCode,\n emailVerificationExpiresAt,\n })\n await user.save()\n\n try {\n await sendEmail({\n to: email,\n subject: `Verify your email: ${emailVerificationCode}`,\n html: `\n <p>Welcome to rpcbase!</p>\n <p>Your verification code is <strong>${emailVerificationCode}</strong>. It expires in 10 minutes.</p>\n <p>If you didn't request this, you can ignore this message.</p>\n `,\n text: `Welcome to rpcbase! Your verification code is ${emailVerificationCode}. It expires in 10 minutes. If you didn't request this, you can ignore this message.`,\n })\n } catch (err) {\n console.error(\"failed to send sign-up email\", err)\n\n try {\n await User.deleteOne({ _id: user._id })\n } catch (rollbackErr) {\n console.error(\"failed to roll back user after sign-up email failure\", rollbackErr)\n }\n\n ctx.res.status(500)\n return { success: false, error: \"email_delivery_failed\" }\n }\n\n try {\n await createProvisionedTenant(Tenant, {\n tenantId,\n name: email,\n })\n } catch (err) {\n console.error(\"failed to initialize tenant for user\", err)\n try {\n await User.deleteOne({ _id: user._id })\n } catch (rollbackErr) {\n console.error(\"failed to roll back user after tenant initialization failure\", rollbackErr)\n }\n ctx.res.status(500)\n return { success: false, error: \"tenant_initialization_failed\" }\n }\n\n console.log(\"created new user\", user._id.toString())\n\n return { success: true }\n}\n\nexport default (api: Api<AuthSessionUser>) => {\n api.post(SignUp.ROUTE, signUp)\n}\n"],"mappings":";;;;;;AAYA,IAAa,SAAqF,OAChG,SACA,QACoC;CACpC,MAAM,SAAA,cAA8B,UAAU,OAAO;CAErD,IAAI,CAAC,OAAO,SAAS;EACnB,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAkB;CACpD;CAGA,MAAM,EAAE,OAAO,UAAU,YAAY,gBAAgB,OAAO;CAE5D,IAAI,CAAC,OAAA,GAAM,yBAAA,oBAAA,CAAoB,KAAK,GAClC,OAAO,EAAE,SAAS,KAAK;CAGzB,MAAM,OAAO,MAAM,OAAO,UAAU,UAAU,GAAG;CACjD,MAAM,SAAS,MAAM,OAAO,UAAU,YAAY,GAAG;CAIrD,IAAI,MAFuB,KAAK,QAAQ,EAAE,MAAM,CAAC,GAE/B;EAChB,QAAQ,IAAI,kCAAkC,KAAK;EAGnD,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAc;CAChD;CAEA,MAAM,iBAAiB,MAAM,uBAAuB,QAAQ;CAE5D,MAAM,WAAW,OAAO,WAAW;CAEnC,MAAM,wBAAwB,OAAO,UAAU,GAAG,GAAS,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,GAAG,GAAG;CACvF,MAAM,6BAA6B,IAAI,KAAK,KAAK,IAAI,IAAI,GAAc;CAEvE,MAAM,OAAO,IAAI,KAAK;EACpB;EACA,UAAU;EACV,SAAS,CAAC,QAAQ;EAClB,aAAa,GACV,WAAW,CAAC,OAAO,EACtB;EACA;EACA;CACF,CAAC;CACD,MAAM,KAAK,KAAK;CAEhB,IAAI;EACF,MAAM,UAAU;GACd,IAAI;GACJ,SAAS,sBAAsB;GAC/B,MAAM;;+CAEmC,sBAAqB;;;GAG9D,MAAM,iDAAiD,sBAAqB;EAC9E,CAAC;CACH,SAAS,KAAK;EACZ,QAAQ,MAAM,gCAAgC,GAAG;EAEjD,IAAI;GACF,MAAM,KAAK,UAAU,EAAE,KAAK,KAAK,IAAI,CAAC;EACxC,SAAS,aAAa;GACpB,QAAQ,MAAM,wDAAwD,WAAW;EACnF;EAEA,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAwB;CAC1D;CAEA,IAAI;EACF,MAAM,wBAAwB,QAAQ;GACpC;GACA,MAAM;EACR,CAAC;CACH,SAAS,KAAK;EACZ,QAAQ,MAAM,wCAAwC,GAAG;EACzD,IAAI;GACF,MAAM,KAAK,UAAU,EAAE,KAAK,KAAK,IAAI,CAAC;EACxC,SAAS,aAAa;GACpB,QAAQ,MAAM,gEAAgE,WAAW;EAC3F;EACA,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAA+B;CACjE;CAEA,QAAQ,IAAI,oBAAoB,KAAK,IAAI,SAAS,CAAC;CAEnD,OAAO,EAAE,SAAS,KAAK;AACzB;AAEA,IAAA,mBAAgB,QAA8B;CAC5C,IAAI,KAAK,OAAc,MAAM;AAC/B"}
@@ -1,4 +1,4 @@
1
- import { a as string, i as object, n as boolean } from "./schemas-BgOpQqUv.js";
1
+ import { a as string, i as object, n as boolean } from "./schemas-CMgO_xn9.js";
2
2
  import { r as restrictSessionMiddleware } from "./middleware-BT3Uput1.js";
3
3
  import { t as AUTHENTICATED_TENANT_ID_HEADER } from "./session-BQ06Yo3C.js";
4
4
  //#region src/api/set-active-account/index.ts
@@ -64,4 +64,4 @@ var handler_default = (api) => {
64
64
  //#endregion
65
65
  export { handler_default as default };
66
66
 
67
- //# sourceMappingURL=handler-J2FOxq-2.js.map
67
+ //# sourceMappingURL=handler-CF3fSh8e.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler-CF3fSh8e.js","names":[],"sources":["../src/api/set-active-account/index.ts","../src/api/set-active-account/handler.ts"],"sourcesContent":["import { z } from \"zod\"\n\n\nexport const ROUTE = \"/api/rb/auth/set-active-account\"\n\nexport const requestSchema = z.object({\n tenantId: z.string().min(1, \"Tenant is required\"),\n})\n\nexport type RequestPayload = z.infer<typeof requestSchema>\n\nexport const responseSchema = z.object({\n success: z.boolean(),\n error: z.string().optional(),\n tenantId: z.string().optional(),\n})\n\nexport type ResponsePayload = z.infer<typeof responseSchema>\n","import { Api, ApiHandler, Ctx } from \"@rpcbase/api\"\n\nimport { restrictSessionMiddleware } from \"../../middleware\"\nimport { AUTHENTICATED_TENANT_ID_HEADER } from \"../../session\"\nimport type { AuthSessionUser } from \"../../types\"\n\nimport * as SetActiveAccount from \"./index\"\n\n\nconst setActiveAccount: ApiHandler<\n SetActiveAccount.RequestPayload,\n SetActiveAccount.ResponsePayload,\n AuthSessionUser\n> = async(\n payload,\n ctx: Ctx<AuthSessionUser>\n): Promise<SetActiveAccount.ResponsePayload> => {\n const parsed = SetActiveAccount.requestSchema.safeParse(payload)\n\n if (!parsed.success) {\n ctx.res.status(400)\n return { success: false, error: \"invalid_payload\" }\n }\n\n const sessionUser = ctx.req.session?.user\n if (!sessionUser?.id) {\n ctx.res.status(401)\n return { success: false, error: \"unauthorized\" }\n }\n\n const tenantId = parsed.data.tenantId.trim()\n const signedInTenants = Array.isArray(sessionUser.signedInTenants)\n ? sessionUser.signedInTenants.map(String)\n : []\n\n if (signedInTenants.length > 0 && !signedInTenants.includes(tenantId)) {\n ctx.res.status(403)\n return { success: false, error: \"invalid_account\" }\n }\n\n if (signedInTenants.length === 0) {\n const currentTenantId = typeof sessionUser.currentTenantId === \"string\" ? sessionUser.currentTenantId.trim() : \"\"\n if (!currentTenantId || currentTenantId !== tenantId) {\n ctx.res.status(403)\n return { success: false, error: \"invalid_account\" }\n }\n }\n\n ctx.req.session.user = {\n ...sessionUser,\n currentTenantId: tenantId,\n }\n ctx.res.setHeader(AUTHENTICATED_TENANT_ID_HEADER, tenantId)\n\n return { success: true, tenantId }\n}\n\nexport default (api: Api<AuthSessionUser>) => {\n api.use(SetActiveAccount.ROUTE, restrictSessionMiddleware)\n api.post(SetActiveAccount.ROUTE, setActiveAccount)\n}\n"],"mappings":";;;;AAGA,IAAa,QAAQ;AAErB,IAAa,gBAAgB,OAAS,EACpC,UAAU,OAAS,CAAC,CAAC,IAAI,GAAG,oBAAoB,EAClD,CAAC;AAI6B,OAAS;CACrC,SAAS,QAAU;CACnB,OAAO,OAAS,CAAC,CAAC,SAAS;CAC3B,UAAU,OAAS,CAAC,CAAC,SAAS;AAChC,CAAC;;;ACND,IAAM,mBAIF,OACF,SACA,QAC8C;CAC9C,MAAM,SAAA,cAAwC,UAAU,OAAO;CAE/D,IAAI,CAAC,OAAO,SAAS;EACnB,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAkB;CACpD;CAEA,MAAM,cAAc,IAAI,IAAI,SAAS;CACrC,IAAI,CAAC,aAAa,IAAI;EACpB,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAe;CACjD;CAEA,MAAM,WAAW,OAAO,KAAK,SAAS,KAAK;CAC3C,MAAM,kBAAkB,MAAM,QAAQ,YAAY,eAAe,IAC7D,YAAY,gBAAgB,IAAI,MAAM,IACtC,CAAA;CAEJ,IAAI,gBAAgB,SAAS,KAAK,CAAC,gBAAgB,SAAS,QAAQ,GAAG;EACrE,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAkB;CACpD;CAEA,IAAI,gBAAgB,WAAW,GAAG;EAChC,MAAM,kBAAkB,OAAO,YAAY,oBAAoB,WAAW,YAAY,gBAAgB,KAAK,IAAI;EAC/G,IAAI,CAAC,mBAAmB,oBAAoB,UAAU;GACpD,IAAI,IAAI,OAAO,GAAG;GAClB,OAAO;IAAE,SAAS;IAAO,OAAO;GAAkB;EACpD;CACF;CAEA,IAAI,IAAI,QAAQ,OAAO;EACrB,GAAG;EACH,iBAAiB;CACnB;CACA,IAAI,IAAI,UAAU,gCAAgC,QAAQ;CAE1D,OAAO;EAAE,SAAS;EAAM;CAAS;AACnC;AAEA,IAAA,mBAAgB,QAA8B;CAC5C,IAAI,IAAI,OAAwB,yBAAyB;CACzD,IAAI,KAAK,OAAwB,gBAAgB;AACnD"}
@@ -1,4 +1,4 @@
1
- import { n as requestSchema, t as ROUTE } from "./sign-in-BkhQovKN.js";
1
+ import { n as requestSchema, t as ROUTE } from "./sign-in-DYq3bJeH.js";
2
2
  import { n as completeAuthSignIn } from "./session-BQ06Yo3C.js";
3
3
  import { models } from "@rpcbase/db";
4
4
  import { verifyPasswordFromStorage } from "@rpcbase/server";
@@ -71,4 +71,4 @@ var handler_default = (api) => {
71
71
  //#endregion
72
72
  export { handler_default as default };
73
73
 
74
- //# sourceMappingURL=handler-DH9FPTNh.js.map
74
+ //# sourceMappingURL=handler-D4ui5jV4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler-D4ui5jV4.js","names":[],"sources":["../src/api/sign-in/handler.ts"],"sourcesContent":["import { Api, ApiHandler, Ctx } from \"@rpcbase/api\"\nimport { models } from \"@rpcbase/db\"\nimport { verifyPasswordFromStorage } from \"@rpcbase/server\"\n\nimport { completeAuthSignIn } from \"../../session\"\nimport type { AuthSessionUser } from \"../../types\"\n\nimport * as SignIn from \"./index\"\n\n\nconst signIn: ApiHandler<SignIn.RequestPayload, SignIn.ResponsePayload, AuthSessionUser> = async(\n payload,\n ctx: Ctx<AuthSessionUser>\n): Promise<SignIn.ResponsePayload> => {\n const User = await models.getGlobal(\"RBUser\", ctx)\n\n const parsed = SignIn.requestSchema.safeParse(payload)\n\n if (!parsed.success) {\n ctx.res.status(400)\n return { success: false, error: \"invalid_payload\" }\n }\n\n const { email, password } = parsed.data\n\n const user = await User.findOne({ email }, { password: 1, tenants: 1, tenantRoles: 1 })\n\n if (!user?.password) {\n ctx.res.status(401)\n return { success: false, error: \"invalid_credentials\" }\n }\n\n const stored = String(user.password)\n const passwordMatches = await verifyPasswordFromStorage(password, stored)\n\n if (!passwordMatches) {\n if (!stored.startsWith(\"$scrypt$\")) {\n console.warn(\"auth::sign-in invalid stored password format\", user._id.toString())\n }\n ctx.res.status(401)\n return { success: false, error: \"invalid_credentials\" }\n }\n\n const signedInTenants = (user.tenants || []).map(String)\n const defaultTenantId = signedInTenants[0]\n if (!defaultTenantId) {\n ctx.res.status(500)\n return { success: false, error: \"tenant_unavailable\" }\n }\n const tenantId = defaultTenantId\n const tenantRolesMap = user.get(\"tenantRoles\") as Map<string, string[]> | undefined\n const tenantRoles = tenantRolesMap ? Object.fromEntries(tenantRolesMap.entries()) : undefined\n\n if (!completeAuthSignIn(ctx, {\n userId: user._id.toString(),\n currentTenantId: tenantId,\n signedInTenants: signedInTenants.length ? signedInTenants : [tenantId],\n tenantRoles,\n })) {\n ctx.res.status(500)\n return { success: false, error: \"session_unavailable\" }\n }\n\n return { success: true, userId: user._id.toString(), tenantId }\n}\n\nexport default (api: Api<AuthSessionUser>) => {\n api.post(SignIn.ROUTE, signIn)\n}\n"],"mappings":";;;;;AAUA,IAAM,SAAqF,OACzF,SACA,QACoC;CACpC,MAAM,OAAO,MAAM,OAAO,UAAU,UAAU,GAAG;CAEjD,MAAM,SAAA,cAA8B,UAAU,OAAO;CAErD,IAAI,CAAC,OAAO,SAAS;EACnB,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAkB;CACpD;CAEA,MAAM,EAAE,OAAO,aAAa,OAAO;CAEnC,MAAM,OAAO,MAAM,KAAK,QAAQ,EAAE,MAAM,GAAG;EAAE,UAAU;EAAG,SAAS;EAAG,aAAa;CAAE,CAAC;CAEtF,IAAI,CAAC,MAAM,UAAU;EACnB,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAsB;CACxD;CAEA,MAAM,SAAS,OAAO,KAAK,QAAQ;CAGnC,IAAI,CAAC,MAFyB,0BAA0B,UAAU,MAAM,GAElD;EACpB,IAAI,CAAC,OAAO,WAAW,UAAU,GAC/B,QAAQ,KAAK,gDAAgD,KAAK,IAAI,SAAS,CAAC;EAElF,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAsB;CACxD;CAEA,MAAM,mBAAmB,KAAK,WAAW,CAAA,EAAA,CAAI,IAAI,MAAM;CACvD,MAAM,kBAAkB,gBAAgB;CACxC,IAAI,CAAC,iBAAiB;EACpB,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAqB;CACvD;CACA,MAAM,WAAW;CACjB,MAAM,iBAAiB,KAAK,IAAI,aAAa;CAC7C,MAAM,cAAc,iBAAiB,OAAO,YAAY,eAAe,QAAQ,CAAC,IAAI,KAAA;CAEpF,IAAI,CAAC,mBAAmB,KAAK;EAC3B,QAAQ,KAAK,IAAI,SAAS;EAC1B,iBAAiB;EACjB,iBAAiB,gBAAgB,SAAS,kBAAkB,CAAC,QAAQ;EACrE;CACF,CAAC,GAAG;EACF,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAsB;CACxD;CAEA,OAAO;EAAE,SAAS;EAAM,QAAQ,KAAK,IAAI,SAAS;EAAG;CAAS;AAChE;AAEA,IAAA,mBAAgB,QAA8B;CAC5C,IAAI,KAAK,OAAc,MAAM;AAC/B"}
@@ -1,4 +1,4 @@
1
- import { i as object, n as boolean } from "./schemas-BgOpQqUv.js";
1
+ import { i as object, n as boolean } from "./schemas-CMgO_xn9.js";
2
2
  //#region src/api/sign-out/index.ts
3
3
  var ROUTE = "/api/rb/auth/sign-out";
4
4
  object({});
@@ -16,4 +16,4 @@ var handler_default = (api) => {
16
16
  //#endregion
17
17
  export { handler_default as default };
18
18
 
19
- //# sourceMappingURL=handler-DQvdRpG2.js.map
19
+ //# sourceMappingURL=handler-DBbjgU-f.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler-DBbjgU-f.js","names":[],"sources":["../src/api/sign-out/index.ts","../src/api/sign-out/handler.ts"],"sourcesContent":["import { z } from \"zod\"\n\n\nexport const ROUTE = \"/api/rb/auth/sign-out\"\n\n// No request payload needed for signout\nexport const requestSchema = z.object({})\n\nexport type RequestPayload = z.infer<typeof requestSchema>;\n\nexport const responseSchema = z.object({\n success: z.boolean()\n})\n\nexport type ResponsePayload = z.infer<typeof responseSchema>;\n","import { Api, Ctx } from \"@rpcbase/api\"\n\nimport * as SignOut from \"./index\"\n\n\nconst handleSignOut = async(_: SignOut.RequestPayload, ctx: Ctx): Promise<SignOut.ResponsePayload> => {\n // Destroy the session\n if (!ctx.req.session) {\n return { success: true }\n }\n\n await new Promise<void>((resolve) => ctx.req.session!.destroy(() => resolve()))\n\n return {\n success: true\n }\n}\n\nexport default (api: Api) => {\n api.post(SignOut.ROUTE, handleSignOut)\n}\n"],"mappings":";;AAGA,IAAa,QAAQ;AAGQ,OAAS,CAAC,CAAC;AAIV,OAAS,EACrC,SAAS,QAAU,EACrB,CAAC;;;ACPD,IAAM,gBAAgB,OAAM,GAA2B,QAA+C;CAEpG,IAAI,CAAC,IAAI,IAAI,SACX,OAAO,EAAE,SAAS,KAAK;CAGzB,MAAM,IAAI,SAAe,YAAY,IAAI,IAAI,QAAS,cAAc,QAAQ,CAAC,CAAC;CAE9E,OAAO,EACL,SAAS,KACX;AACF;AAEA,IAAA,mBAAgB,QAAa;CAC3B,IAAI,KAAK,OAAe,aAAa;AACvC"}
@@ -1,4 +1,4 @@
1
- import { a as string, i as object, n as boolean, r as number } from "./schemas-BgOpQqUv.js";
1
+ import { a as string, i as object, n as boolean, r as number } from "./schemas-CMgO_xn9.js";
2
2
  import { t as email_validation_exports } from "./email-validation/index.js";
3
3
  import crypto from "crypto";
4
4
  import { models } from "@rpcbase/db";
@@ -45,7 +45,7 @@ var requestPasswordReset = async (payload, ctx) => {
45
45
  }
46
46
  const User = await models.getGlobal("RBUser", ctx);
47
47
  const requestedAt = /* @__PURE__ */ new Date();
48
- const cooldownEligibleExpiresAt = new Date(requestedAt.getTime() + (PASSWORD_RESET_CODE_TTL_SECONDS - 60) * 1e3);
48
+ const cooldownEligibleExpiresAt = new Date(requestedAt.getTime() + 54e4);
49
49
  const passwordResetCode = crypto.randomInt(0, 1e6).toString().padStart(6, "0");
50
50
  const passwordResetCodeExpiresAt = new Date(requestedAt.getTime() + PASSWORD_RESET_CODE_TTL_SECONDS * 1e3);
51
51
  const user = await User.findOneAndUpdate({
@@ -130,4 +130,4 @@ var handler_default = (api) => {
130
130
  //#endregion
131
131
  export { PASSWORD_RESET_COOLDOWN_SECONDS, handler_default as default, requestPasswordReset };
132
132
 
133
- //# sourceMappingURL=handler-BY6DP3QP.js.map
133
+ //# sourceMappingURL=handler-Dbw6BOmj.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler-Dbw6BOmj.js","names":[],"sources":["../src/api/request-password-reset/index.ts","../src/api/request-password-reset/handler.ts"],"sourcesContent":["import { z } from \"zod\"\n\n\nexport const ROUTE = \"/api/rb/auth/request-password-reset\"\n\nexport const requestSchema = z.object({\n email: z.string().email(),\n})\n\nexport type RequestPayload = z.infer<typeof requestSchema>\n\nexport const responseSchema = z.object({\n success: z.boolean(),\n error: z.string().optional(),\n retryAfterSeconds: z.number().int().positive().optional(),\n})\n\nexport type ResponsePayload = z.infer<typeof responseSchema>\n","import crypto from \"crypto\"\n\nimport { Api, ApiHandler, Ctx } from \"@rpcbase/api\"\nimport { models } from \"@rpcbase/db\"\nimport { sendEmail } from \"@rpcbase/server\"\n\nimport { isEmailAddressValid } from \"../../email-validation\"\nimport type { AuthSessionUser } from \"../../types\"\n\nimport * as RequestPasswordReset from \"./index\"\n\n\nexport const PASSWORD_RESET_COOLDOWN_SECONDS = 60\nconst PASSWORD_RESET_CODE_TTL_SECONDS = 10 * 60\n\nconst maskEmailForLog = (email: string) => {\n const [localRaw, domainRaw = \"\"] = email.split(\"@\")\n const local = localRaw || \"\"\n const domain = domainRaw || \"\"\n const localPrefix = local.slice(0, Math.min(3, local.length))\n const localMask = \"*\".repeat(Math.max(5, local.length - localPrefix.length))\n\n if (!domain) {\n return `${localPrefix}${localMask}@****`\n }\n\n const domainTailLength = Math.min(7, domain.length)\n const domainTail = domain.slice(-domainTailLength)\n const domainMask = \"*\".repeat(Math.max(4, domain.length - domainTailLength))\n\n return `${localPrefix}${localMask}@${domainMask}${domainTail}`\n}\n\n\nexport const requestPasswordReset: ApiHandler<\n RequestPasswordReset.RequestPayload,\n RequestPasswordReset.ResponsePayload,\n AuthSessionUser\n> = async(\n payload,\n ctx: Ctx<AuthSessionUser>\n): Promise<RequestPasswordReset.ResponsePayload> => {\n const parsed = RequestPasswordReset.requestSchema.safeParse(payload)\n\n if (!parsed.success) {\n ctx.res.status(400)\n return { success: false, error: \"invalid_payload\" }\n }\n\n const { email } = parsed.data\n\n if (!await isEmailAddressValid(email)) {\n ctx.res.setHeader(\"Retry-After\", String(PASSWORD_RESET_COOLDOWN_SECONDS))\n return { success: true, retryAfterSeconds: PASSWORD_RESET_COOLDOWN_SECONDS }\n }\n\n const User = await models.getGlobal(\"RBUser\", ctx)\n const requestedAt = new Date()\n const cooldownEligibleExpiresAt = new Date(\n requestedAt.getTime() + (PASSWORD_RESET_CODE_TTL_SECONDS - PASSWORD_RESET_COOLDOWN_SECONDS) * 1000,\n )\n const passwordResetCode = crypto.randomInt(0, 1_000_000).toString().padStart(6, \"0\")\n const passwordResetCodeExpiresAt = new Date(requestedAt.getTime() + PASSWORD_RESET_CODE_TTL_SECONDS * 1000)\n\n const user = await User.findOneAndUpdate(\n {\n email,\n $or: [\n { passwordResetCodeExpiresAt: { $exists: false } },\n { passwordResetCodeExpiresAt: { $lte: cooldownEligibleExpiresAt } },\n ],\n },\n {\n $set: {\n passwordResetCode,\n passwordResetCodeExpiresAt,\n },\n $unset: {\n passwordResetToken: \"\",\n passwordResetTokenExpiresAt: \"\",\n },\n },\n { returnDocument: \"after\" },\n )\n\n ctx.res.setHeader(\"Retry-After\", String(PASSWORD_RESET_COOLDOWN_SECONDS))\n\n if (!user) {\n const existingUser = await User.findOne({ email }, { _id: 1 })\n\n if (!existingUser) {\n try {\n console.info(`sending password reset account notice to email ${maskEmailForLog(email)}`)\n await sendEmail({\n to: email,\n subject: \"Password reset request\",\n html: `\n <p>Hello,</p>\n <p>A password reset code has been requested for this email address, but there doesn't appear to be any account associated with it.</p>\n <p>If you didn't request this, you can ignore this message.</p>\n <p>If you're having trouble accessing your account, please contact support.</p>\n `,\n text: \"Hello, A password reset code has been requested for this email address, but there doesn't appear to be any account associated with it. If you didn't request this, you can ignore this message. If you're having trouble accessing your account, please contact support.\",\n })\n } catch (err) {\n console.error(\"failed to send password reset account notice email\", err)\n ctx.res.status(500)\n return { success: false, error: \"email_delivery_failed\" }\n }\n }\n\n return { success: true, retryAfterSeconds: PASSWORD_RESET_COOLDOWN_SECONDS }\n }\n\n try {\n console.info(`sending password reset to email ${maskEmailForLog(email)}`)\n await sendEmail({\n to: email,\n subject: `Your password reset code: ${passwordResetCode}`,\n html: `\n <p>Your password reset code is <strong>${passwordResetCode}</strong>. It expires in 10 minutes.</p>\n <p>If you didn't request this, you can ignore this message.</p>\n `,\n text: `Your password reset code is ${passwordResetCode}. It expires in 10 minutes. If you didn't request this, you can ignore this message.`,\n })\n } catch (err) {\n console.error(\"failed to send password reset email\", err)\n\n try {\n const releaseResult = await User.updateOne(\n { _id: user._id, passwordResetCode },\n {\n $unset: {\n passwordResetCode: \"\",\n passwordResetCodeExpiresAt: \"\",\n },\n },\n )\n if (releaseResult.modifiedCount > 0) {\n ctx.res.removeHeader(\"Retry-After\")\n }\n } catch (releaseErr) {\n console.error(\"failed to release password reset cooldown\", releaseErr)\n }\n\n ctx.res.status(500)\n return { success: false, error: \"email_delivery_failed\" }\n }\n\n return { success: true, retryAfterSeconds: PASSWORD_RESET_COOLDOWN_SECONDS }\n}\n\nexport default (api: Api<AuthSessionUser>) => {\n api.post(RequestPasswordReset.ROUTE, requestPasswordReset)\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { a as string, i as object, n as boolean } from "./schemas-BgOpQqUv.js";
1
+ import { a as string, i as object, n as boolean } from "./schemas-CMgO_xn9.js";
2
2
  import { models } from "@rpcbase/db";
3
3
  import { hashPasswordForStorage } from "@rpcbase/server";
4
4
  //#region src/api/set-new-password/index.ts
@@ -48,4 +48,4 @@ var handler_default = (api) => {
48
48
  //#endregion
49
49
  export { handler_default as default };
50
50
 
51
- //# sourceMappingURL=handler-DoyR_l2O.js.map
51
+ //# sourceMappingURL=handler-DgIcxthg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler-DgIcxthg.js","names":[],"sources":["../src/api/set-new-password/index.ts","../src/api/set-new-password/handler.ts"],"sourcesContent":["import { z } from \"zod\"\n\n\nexport const ROUTE = \"/api/rb/auth/set-new-password\"\n\nexport const requestSchema = z.object({\n email: z.string().email(),\n resetToken: z.string().min(1),\n password: z.string().min(8, { message: \"Password must be at least 8 characters long.\" }),\n})\n\nexport type RequestPayload = z.infer<typeof requestSchema>\n\nexport const responseSchema = z.object({\n success: z.boolean(),\n error: z.string().optional(),\n})\n\nexport type ResponsePayload = z.infer<typeof responseSchema>\n","import { Api, ApiHandler, Ctx } from \"@rpcbase/api\"\nimport { models } from \"@rpcbase/db\"\nimport { hashPasswordForStorage } from \"@rpcbase/server\"\n\nimport type { AuthSessionUser } from \"../../types\"\n\nimport * as SetNewPassword from \"./index\"\n\n\nconst setNewPassword: ApiHandler<\n SetNewPassword.RequestPayload,\n SetNewPassword.ResponsePayload,\n AuthSessionUser\n> = async(\n payload,\n ctx: Ctx<AuthSessionUser>\n): Promise<SetNewPassword.ResponsePayload> => {\n const User = await models.getGlobal(\"RBUser\", ctx)\n\n const parsed = SetNewPassword.requestSchema.safeParse(payload)\n\n if (!parsed.success) {\n ctx.res.status(400)\n return { success: false, error: \"invalid_payload\" }\n }\n\n const { email, resetToken, password } = parsed.data\n\n const user = await User.findOne({ email })\n const storedToken = user?.passwordResetToken\n const tokenExpiresAt = user?.passwordResetTokenExpiresAt\n const isExpired = tokenExpiresAt instanceof Date && tokenExpiresAt.getTime() < Date.now()\n\n if (!user || !storedToken || storedToken !== resetToken || isExpired) {\n ctx.res.status(400)\n return { success: false, error: \"invalid_token\" }\n }\n\n const hashedPassword = await hashPasswordForStorage(password)\n user.password = hashedPassword\n user.passwordResetToken = undefined\n user.passwordResetTokenExpiresAt = undefined\n await user.save()\n\n return { success: true }\n}\n\nexport default (api: Api<AuthSessionUser>) => {\n api.post(SetNewPassword.ROUTE, setNewPassword)\n}\n"],"mappings":";;;;AAGA,IAAa,QAAQ;AAErB,IAAa,gBAAgB,OAAS;CACpC,OAAO,OAAS,CAAC,CAAC,MAAM;CACxB,YAAY,OAAS,CAAC,CAAC,IAAI,CAAC;CAC5B,UAAU,OAAS,CAAC,CAAC,IAAI,GAAG,EAAE,SAAS,+CAA+C,CAAC;AACzF,CAAC;AAI6B,OAAS;CACrC,SAAS,QAAU;CACnB,OAAO,OAAS,CAAC,CAAC,SAAS;AAC7B,CAAC;;;ACPD,IAAM,iBAIF,OACF,SACA,QAC4C;CAC5C,MAAM,OAAO,MAAM,OAAO,UAAU,UAAU,GAAG;CAEjD,MAAM,SAAA,cAAsC,UAAU,OAAO;CAE7D,IAAI,CAAC,OAAO,SAAS;EACnB,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAkB;CACpD;CAEA,MAAM,EAAE,OAAO,YAAY,aAAa,OAAO;CAE/C,MAAM,OAAO,MAAM,KAAK,QAAQ,EAAE,MAAM,CAAC;CACzC,MAAM,cAAc,MAAM;CAC1B,MAAM,iBAAiB,MAAM;CAC7B,MAAM,YAAY,0BAA0B,QAAQ,eAAe,QAAQ,IAAI,KAAK,IAAI;CAExF,IAAI,CAAC,QAAQ,CAAC,eAAe,gBAAgB,cAAc,WAAW;EACpE,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAgB;CAClD;CAGA,KAAK,WAAW,MADa,uBAAuB,QAAQ;CAE5D,KAAK,qBAAqB,KAAA;CAC1B,KAAK,8BAA8B,KAAA;CACnC,MAAM,KAAK,KAAK;CAEhB,OAAO,EAAE,SAAS,KAAK;AACzB;AAEA,IAAA,mBAAgB,QAA8B;CAC5C,IAAI,KAAK,OAAsB,cAAc;AAC/C"}
@@ -1,4 +1,4 @@
1
- import { a as string, i as object, n as boolean } from "./schemas-BgOpQqUv.js";
1
+ import { a as string, i as object, n as boolean } from "./schemas-CMgO_xn9.js";
2
2
  import crypto from "crypto";
3
3
  import { models } from "@rpcbase/db";
4
4
  //#region src/api/verify-password-reset-otp/index.ts
@@ -40,7 +40,7 @@ var verifyPasswordResetOtp = async (payload, ctx) => {
40
40
  user.passwordResetCode = void 0;
41
41
  user.passwordResetCodeExpiresAt = void 0;
42
42
  user.passwordResetToken = resetToken;
43
- user.passwordResetTokenExpiresAt = new Date(Date.now() + 900 * 1e3);
43
+ user.passwordResetTokenExpiresAt = new Date(Date.now() + 9e5);
44
44
  await user.save();
45
45
  return {
46
46
  success: true,
@@ -53,4 +53,4 @@ var handler_default = (api) => {
53
53
  //#endregion
54
54
  export { handler_default as default };
55
55
 
56
- //# sourceMappingURL=handler-DAfIloZR.js.map
56
+ //# sourceMappingURL=handler-iT2eSHpE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler-iT2eSHpE.js","names":[],"sources":["../src/api/verify-password-reset-otp/index.ts","../src/api/verify-password-reset-otp/handler.ts"],"sourcesContent":["import { z } from \"zod\"\n\n\nexport const ROUTE = \"/api/rb/auth/verify-password-reset-otp\"\n\nexport const requestSchema = z.object({\n email: z.string().email(),\n code: z.string().length(6, \"Code must be 6 digits\"),\n})\n\nexport type RequestPayload = z.infer<typeof requestSchema>\n\nexport const responseSchema = z.object({\n success: z.boolean(),\n error: z.string().optional(),\n resetToken: z.string().optional(),\n})\n\nexport type ResponsePayload = z.infer<typeof responseSchema>\n","import crypto from \"crypto\"\n\nimport { Api, ApiHandler, Ctx } from \"@rpcbase/api\"\nimport { models } from \"@rpcbase/db\"\n\nimport type { AuthSessionUser } from \"../../types\"\n\nimport * as VerifyPasswordResetOtp from \"./index\"\n\n\nconst verifyPasswordResetOtp: ApiHandler<\n VerifyPasswordResetOtp.RequestPayload,\n VerifyPasswordResetOtp.ResponsePayload,\n AuthSessionUser\n> = async(\n payload,\n ctx: Ctx<AuthSessionUser>\n): Promise<VerifyPasswordResetOtp.ResponsePayload> => {\n const User = await models.getGlobal(\"RBUser\", ctx)\n\n const parsed = VerifyPasswordResetOtp.requestSchema.safeParse(payload)\n\n if (!parsed.success) {\n ctx.res.status(400)\n return { success: false, error: \"invalid_payload\" }\n }\n\n const { email, code } = parsed.data\n const user = await User.findOne({ email })\n\n const storedCode = user?.passwordResetCode\n const expiresAt = user?.passwordResetCodeExpiresAt\n const isExpired = expiresAt instanceof Date && expiresAt.getTime() < Date.now()\n\n if (!user || !storedCode || storedCode !== code || isExpired) {\n ctx.res.status(400)\n return { success: false, error: \"invalid_code\" }\n }\n\n const resetToken = crypto.randomBytes(24).toString(\"hex\")\n\n user.passwordResetCode = undefined\n user.passwordResetCodeExpiresAt = undefined\n user.passwordResetToken = resetToken\n user.passwordResetTokenExpiresAt = new Date(Date.now() + 15 * 60 * 1000)\n await user.save()\n\n return { success: true, resetToken }\n}\n\nexport default (api: Api<AuthSessionUser>) => {\n api.post(VerifyPasswordResetOtp.ROUTE, verifyPasswordResetOtp)\n}\n"],"mappings":";;;;AAGA,IAAa,QAAQ;AAErB,IAAa,gBAAgB,OAAS;CACpC,OAAO,OAAS,CAAC,CAAC,MAAM;CACxB,MAAM,OAAS,CAAC,CAAC,OAAO,GAAG,uBAAuB;AACpD,CAAC;AAI6B,OAAS;CACrC,SAAS,QAAU;CACnB,OAAO,OAAS,CAAC,CAAC,SAAS;CAC3B,YAAY,OAAS,CAAC,CAAC,SAAS;AAClC,CAAC;;;ACND,IAAM,yBAIF,OACF,SACA,QACoD;CACpD,MAAM,OAAO,MAAM,OAAO,UAAU,UAAU,GAAG;CAEjD,MAAM,SAAA,cAA8C,UAAU,OAAO;CAErE,IAAI,CAAC,OAAO,SAAS;EACnB,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAkB;CACpD;CAEA,MAAM,EAAE,OAAO,SAAS,OAAO;CAC/B,MAAM,OAAO,MAAM,KAAK,QAAQ,EAAE,MAAM,CAAC;CAEzC,MAAM,aAAa,MAAM;CACzB,MAAM,YAAY,MAAM;CACxB,MAAM,YAAY,qBAAqB,QAAQ,UAAU,QAAQ,IAAI,KAAK,IAAI;CAE9E,IAAI,CAAC,QAAQ,CAAC,cAAc,eAAe,QAAQ,WAAW;EAC5D,IAAI,IAAI,OAAO,GAAG;EAClB,OAAO;GAAE,SAAS;GAAO,OAAO;EAAe;CACjD;CAEA,MAAM,aAAa,OAAO,YAAY,EAAE,CAAC,CAAC,SAAS,KAAK;CAExD,KAAK,oBAAoB,KAAA;CACzB,KAAK,6BAA6B,KAAA;CAClC,KAAK,qBAAqB;CAC1B,KAAK,8BAA8B,IAAI,KAAK,KAAK,IAAI,IAAI,GAAc;CACvE,MAAM,KAAK,KAAK;CAEhB,OAAO;EAAE,SAAS;EAAM;CAAW;AACrC;AAEA,IAAA,mBAAgB,QAA8B;CAC5C,IAAI,KAAK,OAA8B,sBAAsB;AAC/D"}