@rpcbase/auth 0.158.0 → 0.160.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 (47) hide show
  1. package/dist/api/request-password-reset/handler.d.ts +4 -1
  2. package/dist/api/request-password-reset/handler.d.ts.map +1 -1
  3. package/dist/api/request-password-reset/index.d.ts +1 -0
  4. package/dist/api/request-password-reset/index.d.ts.map +1 -1
  5. package/dist/api/resend-otp/handler.d.ts +3 -1
  6. package/dist/api/resend-otp/handler.d.ts.map +1 -1
  7. package/dist/api/sign-up/handler.d.ts +3 -1
  8. package/dist/api/sign-up/handler.d.ts.map +1 -1
  9. package/dist/components/ResendCodeButton/index.d.ts +1 -1
  10. package/dist/components/ResendCodeButton/index.d.ts.map +1 -1
  11. package/dist/{handler-DZiCZNkX.js → handler-B2Qn8_Fq.js} +62 -16
  12. package/dist/handler-B2Qn8_Fq.js.map +1 -0
  13. package/dist/{handler-DG8GMWwR.js → handler-BKSik1j0.js} +23 -4
  14. package/dist/handler-BKSik1j0.js.map +1 -0
  15. package/dist/{handler-BlhyOTyk.js → handler-BXvh_Nx4.js} +17 -4
  16. package/dist/handler-BXvh_Nx4.js.map +1 -0
  17. package/dist/{handler-BIFPHnwb.js → handler-B_lItxOC.js} +2 -2
  18. package/dist/{handler-BIFPHnwb.js.map → handler-B_lItxOC.js.map} +1 -1
  19. package/dist/{handler-4-ccxPqk.js → handler-BuwKXMOu.js} +2 -2
  20. package/dist/{handler-4-ccxPqk.js.map → handler-BuwKXMOu.js.map} +1 -1
  21. package/dist/{handler-BOCOLt9O.js → handler-C-hPxnHG.js} +2 -2
  22. package/dist/{handler-BOCOLt9O.js.map → handler-C-hPxnHG.js.map} +1 -1
  23. package/dist/{handler-Y6JMPCW0.js → handler-CoHpAhui.js} +2 -2
  24. package/dist/{handler-Y6JMPCW0.js.map → handler-CoHpAhui.js.map} +1 -1
  25. package/dist/{handler-BvztD8II.js → handler-DfZwgoA4.js} +2 -2
  26. package/dist/{handler-BvztD8II.js.map → handler-DfZwgoA4.js.map} +1 -1
  27. package/dist/{handler-Dbkf3cD8.js → handler-Eyjkxj9l.js} +2 -2
  28. package/dist/{handler-Dbkf3cD8.js.map → handler-Eyjkxj9l.js.map} +1 -1
  29. package/dist/{handler-EYTkh4N4.js → handler-U3df_2Al.js} +2 -2
  30. package/dist/{handler-EYTkh4N4.js.map → handler-U3df_2Al.js.map} +1 -1
  31. package/dist/{index-sfjvVpg9.js → index-1_ZKABa_.js} +2 -2
  32. package/dist/{index-sfjvVpg9.js.map → index-1_ZKABa_.js.map} +1 -1
  33. package/dist/{index-DznfuMJi.js → index-D94-1Zwh.js} +2 -2
  34. package/dist/{index-DznfuMJi.js.map → index-D94-1Zwh.js.map} +1 -1
  35. package/dist/index.d.ts +1 -0
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +100 -28
  38. package/dist/index.js.map +1 -1
  39. package/dist/passwordReset.d.ts +21 -0
  40. package/dist/passwordReset.d.ts.map +1 -0
  41. package/dist/routes.js +1 -1
  42. package/dist/{schemas-BYptELX5.js → schemas--f80aXK7.js} +372 -1
  43. package/dist/{schemas-BYptELX5.js.map → schemas--f80aXK7.js.map} +1 -1
  44. package/package.json +12 -1
  45. package/dist/handler-BlhyOTyk.js.map +0 -1
  46. package/dist/handler-DG8GMWwR.js.map +0 -1
  47. package/dist/handler-DZiCZNkX.js.map +0 -1
@@ -1,5 +1,8 @@
1
- import { Api } from '@rpcbase/api';
1
+ import { Api, ApiHandler } from '@rpcbase/api';
2
2
  import { AuthSessionUser } from '../../types';
3
+ import * as RequestPasswordReset from "./index";
4
+ export declare const PASSWORD_RESET_COOLDOWN_SECONDS = 60;
5
+ export declare const requestPasswordReset: ApiHandler<RequestPasswordReset.RequestPayload, RequestPasswordReset.ResponsePayload, AuthSessionUser>;
3
6
  declare const _default: (api: Api<AuthSessionUser>) => void;
4
7
  export default _default;
5
8
  //# sourceMappingURL=handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/api/request-password-reset/handler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAmB,MAAM,cAAc,CAAA;AAInD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;yBA2ElC,KAAK,GAAG,CAAC,eAAe,CAAC;AAAzC,wBAEC"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/api/request-password-reset/handler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAE,UAAU,EAAO,MAAM,cAAc,CAAA;AAInD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAElD,OAAO,KAAK,oBAAoB,MAAM,SAAS,CAAA;AAG/C,eAAO,MAAM,+BAA+B,KAAK,CAAA;AAsBjD,eAAO,MAAM,oBAAoB,EAAE,UAAU,CAC3C,oBAAoB,CAAC,cAAc,EACnC,oBAAoB,CAAC,eAAe,EACpC,eAAe,CAqFhB,CAAA;yBAEe,KAAK,GAAG,CAAC,eAAe,CAAC;AAAzC,wBAEC"}
@@ -7,6 +7,7 @@ export type RequestPayload = z.infer<typeof requestSchema>;
7
7
  export declare const responseSchema: z.ZodObject<{
8
8
  success: z.ZodBoolean;
9
9
  error: z.ZodOptional<z.ZodString>;
10
+ retryAfterSeconds: z.ZodOptional<z.ZodNumber>;
10
11
  }, z.core.$strip>;
11
12
  export type ResponsePayload = z.infer<typeof responseSchema>;
12
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/api/request-password-reset/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,KAAK,wCAAwC,CAAA;AAE1D,eAAO,MAAM,aAAa;;iBAExB,CAAA;AAEF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAA;AAE1D,eAAO,MAAM,cAAc;;;iBAGzB,CAAA;AAEF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/api/request-password-reset/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,KAAK,wCAAwC,CAAA;AAE1D,eAAO,MAAM,aAAa;;iBAExB,CAAA;AAEF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAA;AAE1D,eAAO,MAAM,cAAc;;;;iBAIzB,CAAA;AAEF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA"}
@@ -1,5 +1,7 @@
1
- import { Api } from '@rpcbase/api';
1
+ import { Api, ApiHandler } from '@rpcbase/api';
2
2
  import { AuthSessionUser } from '../../types';
3
+ import * as ResendOtp from "./index";
4
+ export declare const resendOtp: ApiHandler<ResendOtp.RequestPayload, ResendOtp.ResponsePayload, AuthSessionUser>;
3
5
  declare const _default: (api: Api<AuthSessionUser>) => void;
4
6
  export default _default;
5
7
  //# sourceMappingURL=handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/api/resend-otp/handler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAmB,MAAM,cAAc,CAAA;AAInD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;yBAqDlC,KAAK,GAAG,CAAC,eAAe,CAAC;AAAzC,wBAEC"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/api/resend-otp/handler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAE,UAAU,EAAO,MAAM,cAAc,CAAA;AAInD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAElD,OAAO,KAAK,SAAS,MAAM,SAAS,CAAA;AAGpC,eAAO,MAAM,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,cAAc,EAAE,SAAS,CAAC,eAAe,EAAE,eAAe,CA+DtG,CAAA;yBAEe,KAAK,GAAG,CAAC,eAAe,CAAC;AAAzC,wBAEC"}
@@ -1,5 +1,7 @@
1
- import { Api } from '@rpcbase/api';
1
+ import { Api, ApiHandler } from '@rpcbase/api';
2
2
  import { AuthSessionUser } from '../../types';
3
+ import * as SignUp from "./index";
4
+ export declare const signUp: ApiHandler<SignUp.RequestPayload, SignUp.ResponsePayload, AuthSessionUser>;
3
5
  declare const _default: (api: Api<AuthSessionUser>) => void;
4
6
  export default _default;
5
7
  //# sourceMappingURL=handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/api/sign-up/handler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAmB,MAAM,cAAc,CAAA;AAInD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;yBAiFlC,KAAK,GAAG,CAAC,eAAe,CAAC;AAAzC,wBAEC"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/api/sign-up/handler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAO,UAAU,EAAE,MAAM,cAAc,CAAA;AAInD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAElD,OAAO,KAAK,MAAM,MAAM,SAAS,CAAA;AAGjC,eAAO,MAAM,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,eAAe,EAAE,eAAe,CAmF7F,CAAA;yBAEe,KAAK,GAAG,CAAC,eAAe,CAAC;AAAzC,wBAEC"}
@@ -1,4 +1,4 @@
1
- export declare const useResendCountdown: (seconds?: number) => {
1
+ export declare const useResendCountdown: (seconds?: number, initiallyCountingDown?: boolean) => {
2
2
  remaining: number;
3
3
  formatted: string;
4
4
  isCountingDown: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ResendCodeButton/index.tsx"],"names":[],"mappings":"AAIA,eAAO,MAAM,kBAAkB,GAAI,gBAAY;;;;;4BAoBF,MAAM;CAelD,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,4CA8CA,CAAA"}
@@ -1,15 +1,18 @@
1
1
  import crypto from "crypto";
2
2
  import { models } from "@rpcbase/db";
3
3
  import { sendEmail } from "@rpcbase/server";
4
- import { o as object, s as string, b as boolean } from "./schemas-BYptELX5.js";
4
+ import { o as object, s as string, n as number, b as boolean } from "./schemas--f80aXK7.js";
5
5
  const Route = "/api/rb/auth/request-password-reset";
6
6
  const requestSchema = object({
7
7
  email: string().email()
8
8
  });
9
9
  object({
10
10
  success: boolean(),
11
- error: string().optional()
11
+ error: string().optional(),
12
+ retryAfterSeconds: number().int().positive().optional()
12
13
  });
14
+ const PASSWORD_RESET_COOLDOWN_SECONDS = 60;
15
+ const PASSWORD_RESET_CODE_TTL_SECONDS = 10 * 60;
13
16
  const maskEmailForLog = (email) => {
14
17
  const [localRaw, domainRaw = ""] = email.split("@");
15
18
  const local = localRaw || "";
@@ -37,21 +40,40 @@ const requestPasswordReset = async (payload, ctx) => {
37
40
  const {
38
41
  email
39
42
  } = parsed.data;
40
- const user = await User.findOne({
41
- email
43
+ const requestedAt = /* @__PURE__ */ new Date();
44
+ const cooldownEligibleExpiresAt = new Date(requestedAt.getTime() + (PASSWORD_RESET_CODE_TTL_SECONDS - PASSWORD_RESET_COOLDOWN_SECONDS) * 1e3);
45
+ const passwordResetCode = crypto.randomInt(0, 1e6).toString().padStart(6, "0");
46
+ const passwordResetCodeExpiresAt = new Date(requestedAt.getTime() + PASSWORD_RESET_CODE_TTL_SECONDS * 1e3);
47
+ const user = await User.findOneAndUpdate({
48
+ email,
49
+ $or: [{
50
+ passwordResetCodeExpiresAt: {
51
+ $exists: false
52
+ }
53
+ }, {
54
+ passwordResetCodeExpiresAt: {
55
+ $lte: cooldownEligibleExpiresAt
56
+ }
57
+ }]
58
+ }, {
59
+ $set: {
60
+ passwordResetCode,
61
+ passwordResetCodeExpiresAt
62
+ },
63
+ $unset: {
64
+ passwordResetToken: "",
65
+ passwordResetTokenExpiresAt: ""
66
+ }
67
+ }, {
68
+ returnDocument: "after"
42
69
  });
70
+ ctx.res.setHeader("Retry-After", String(PASSWORD_RESET_COOLDOWN_SECONDS));
43
71
  if (!user) {
44
72
  return {
45
- success: true
73
+ success: true,
74
+ retryAfterSeconds: PASSWORD_RESET_COOLDOWN_SECONDS
46
75
  };
47
76
  }
48
- const passwordResetCode = crypto.randomInt(0, 1e6).toString().padStart(6, "0");
49
- const passwordResetCodeExpiresAt = new Date(Date.now() + 10 * 60 * 1e3);
50
- user.passwordResetCode = passwordResetCode;
51
- user.passwordResetCodeExpiresAt = passwordResetCodeExpiresAt;
52
- user.passwordResetToken = void 0;
53
- user.passwordResetTokenExpiresAt = void 0;
54
- await user.save();
55
77
  try {
56
78
  console.info(`sending password reset to email ${maskEmailForLog(email)}`);
57
79
  await sendEmail({
@@ -64,16 +86,40 @@ const requestPasswordReset = async (payload, ctx) => {
64
86
  text: `Your password reset code is ${passwordResetCode}. It expires in 10 minutes. If you didn't request this, you can ignore this message.`
65
87
  });
66
88
  } catch (err) {
67
- console.warn("failed to send password reset email", err);
89
+ console.error("failed to send password reset email", err);
90
+ try {
91
+ const releaseResult = await User.updateOne({
92
+ _id: user._id,
93
+ passwordResetCode
94
+ }, {
95
+ $unset: {
96
+ passwordResetCode: "",
97
+ passwordResetCodeExpiresAt: ""
98
+ }
99
+ });
100
+ if (releaseResult.modifiedCount > 0) {
101
+ ctx.res.removeHeader("Retry-After");
102
+ }
103
+ } catch (releaseErr) {
104
+ console.error("failed to release password reset cooldown", releaseErr);
105
+ }
106
+ ctx.res.status(500);
107
+ return {
108
+ success: false,
109
+ error: "email_delivery_failed"
110
+ };
68
111
  }
69
112
  return {
70
- success: true
113
+ success: true,
114
+ retryAfterSeconds: PASSWORD_RESET_COOLDOWN_SECONDS
71
115
  };
72
116
  };
73
117
  const handler = (api) => {
74
118
  api.post(Route, requestPasswordReset);
75
119
  };
76
120
  export {
77
- handler as default
121
+ PASSWORD_RESET_COOLDOWN_SECONDS,
122
+ handler as default,
123
+ requestPasswordReset
78
124
  };
79
- //# sourceMappingURL=handler-DZiCZNkX.js.map
125
+ //# sourceMappingURL=handler-B2Qn8_Fq.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler-B2Qn8_Fq.js","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 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 User = await models.getGlobal(\"RBUser\", ctx)\n\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 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 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"],"names":["Route","requestSchema","z","email","string","success","boolean","error","optional","retryAfterSeconds","number","int","positive","PASSWORD_RESET_COOLDOWN_SECONDS","PASSWORD_RESET_CODE_TTL_SECONDS","maskEmailForLog","localRaw","domainRaw","split","local","domain","localPrefix","slice","Math","min","length","localMask","repeat","max","domainTailLength","domainTail","domainMask","requestPasswordReset","payload","ctx","User","models","getGlobal","parsed","RequestPasswordReset","safeParse","res","status","data","requestedAt","Date","cooldownEligibleExpiresAt","getTime","passwordResetCode","crypto","randomInt","toString","padStart","passwordResetCodeExpiresAt","user","findOneAndUpdate","$or","$exists","$lte","$set","$unset","passwordResetToken","passwordResetTokenExpiresAt","returnDocument","setHeader","String","console","info","sendEmail","to","subject","html","text","err","releaseResult","updateOne","_id","modifiedCount","removeHeader","releaseErr","api","post"],"mappings":";;;;AAGO,MAAMA,QAAQ;AAEd,MAAMC,gBAAgBC,OAAS;AAAA,EACpCC,OAAOD,OAAEE,EAASD,MAAAA;AACpB,CAAC;AAI6BD,OAAS;AAAA,EACrCG,SAASH,QAAEI;AAAAA,EACXC,OAAOL,OAAEE,EAASI,SAAAA;AAAAA,EAClBC,mBAAmBP,OAAEQ,EAASC,MAAMC,SAAAA,EAAWJ,SAAAA;AACjD,CAAC;ACJM,MAAMK,kCAAkC;AAC/C,MAAMC,kCAAkC,KAAK;AAE7C,MAAMC,kBAAkBA,CAACZ,UAAkB;AACzC,QAAM,CAACa,UAAUC,YAAY,EAAE,IAAId,MAAMe,MAAM,GAAG;AAClD,QAAMC,QAAQH,YAAY;AAC1B,QAAMI,SAASH,aAAa;AAC5B,QAAMI,cAAcF,MAAMG,MAAM,GAAGC,KAAKC,IAAI,GAAGL,MAAMM,MAAM,CAAC;AAC5D,QAAMC,YAAY,IAAIC,OAAOJ,KAAKK,IAAI,GAAGT,MAAMM,SAASJ,YAAYI,MAAM,CAAC;AAE3E,MAAI,CAACL,QAAQ;AACX,WAAO,GAAGC,WAAW,GAAGK,SAAS;AAAA,EACnC;AAEA,QAAMG,mBAAmBN,KAAKC,IAAI,GAAGJ,OAAOK,MAAM;AAClD,QAAMK,aAAaV,OAAOE,MAAM,CAACO,gBAAgB;AACjD,QAAME,aAAa,IAAIJ,OAAOJ,KAAKK,IAAI,GAAGR,OAAOK,SAASI,gBAAgB,CAAC;AAE3E,SAAO,GAAGR,WAAW,GAAGK,SAAS,IAAIK,UAAU,GAAGD,UAAU;AAC9D;AAGO,MAAME,uBAIT,OACFC,SACAC,QACkD;AAClD,QAAMC,OAAO,MAAMC,OAAOC,UAAU,UAAUH,GAAG;AAEjD,QAAMI,SAASC,cAAmCC,UAAUP,OAAO;AAEnE,MAAI,CAACK,OAAOjC,SAAS;AACnB6B,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAErC,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAM;AAAA,IAAEJ;AAAAA,EAAAA,IAAUmC,OAAOK;AACzB,QAAMC,kCAAkBC,KAAAA;AACxB,QAAMC,4BAA4B,IAAID,KACpCD,YAAYG,aAAajC,kCAAkCD,mCAAmC,GAChG;AACA,QAAMmC,oBAAoBC,OAAOC,UAAU,GAAG,GAAS,EAAEC,WAAWC,SAAS,GAAG,GAAG;AACnF,QAAMC,6BAA6B,IAAIR,KAAKD,YAAYG,QAAAA,IAAYjC,kCAAkC,GAAI;AAE1G,QAAMwC,OAAO,MAAMnB,KAAKoB,iBACtB;AAAA,IACEpD;AAAAA,IACAqD,KAAK,CACH;AAAA,MAAEH,4BAA4B;AAAA,QAAEI,SAAS;AAAA,MAAA;AAAA,IAAM,GAC/C;AAAA,MAAEJ,4BAA4B;AAAA,QAAEK,MAAMZ;AAAAA,MAAAA;AAAAA,IAA0B,CAAG;AAAA,EAAA,GAGvE;AAAA,IACEa,MAAM;AAAA,MACJX;AAAAA,MACAK;AAAAA,IAAAA;AAAAA,IAEFO,QAAQ;AAAA,MACNC,oBAAoB;AAAA,MACpBC,6BAA6B;AAAA,IAAA;AAAA,EAC/B,GAEF;AAAA,IAAEC,gBAAgB;AAAA,EAAA,CACpB;AAEA7B,MAAIO,IAAIuB,UAAU,eAAeC,OAAOpD,+BAA+B,CAAC;AAExE,MAAI,CAACyC,MAAM;AACT,WAAO;AAAA,MAAEjD,SAAS;AAAA,MAAMI,mBAAmBI;AAAAA,IAAAA;AAAAA,EAC7C;AAEA,MAAI;AACFqD,YAAQC,KAAK,mCAAmCpD,gBAAgBZ,KAAK,CAAC,EAAE;AACxE,UAAMiE,UAAU;AAAA,MACdC,IAAIlE;AAAAA,MACJmE,SAAS,6BAA6BtB,iBAAiB;AAAA,MACvDuB,MAAM;AAAA,iDACqCvB,iBAAiB;AAAA;AAAA;AAAA,MAG5DwB,MAAM,+BAA+BxB,iBAAiB;AAAA,IAAA,CACvD;AAAA,EACH,SAASyB,KAAK;AACZP,YAAQ3D,MAAM,uCAAuCkE,GAAG;AAExD,QAAI;AACF,YAAMC,gBAAgB,MAAMvC,KAAKwC,UAC/B;AAAA,QAAEC,KAAKtB,KAAKsB;AAAAA,QAAK5B;AAAAA,MAAAA,GACjB;AAAA,QACEY,QAAQ;AAAA,UACNZ,mBAAmB;AAAA,UACnBK,4BAA4B;AAAA,QAAA;AAAA,MAC9B,CAEJ;AACA,UAAIqB,cAAcG,gBAAgB,GAAG;AACnC3C,YAAIO,IAAIqC,aAAa,aAAa;AAAA,MACpC;AAAA,IACF,SAASC,YAAY;AACnBb,cAAQ3D,MAAM,6CAA6CwE,UAAU;AAAA,IACvE;AAEA7C,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAErC,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,SAAO;AAAA,IAAEF,SAAS;AAAA,IAAMI,mBAAmBI;AAAAA,EAAAA;AAC7C;AAEA,MAAA,UAAe,CAACmE,QAA8B;AAC5CA,MAAIC,KAAK1C,OAA4BP,oBAAoB;AAC3D;"}
@@ -1,7 +1,7 @@
1
1
  import crypto from "crypto";
2
2
  import { models } from "@rpcbase/db";
3
3
  import { sendEmail } from "@rpcbase/server";
4
- import { o as object, s as string, b as boolean } from "./schemas-BYptELX5.js";
4
+ import { o as object, s as string, b as boolean } from "./schemas--f80aXK7.js";
5
5
  const Route = "/api/rb/auth/resend-otp";
6
6
  const requestSchema = object({
7
7
  email: string().email()
@@ -49,7 +49,25 @@ const resendOtp = async (payload, ctx) => {
49
49
  text: `Your verification code is ${emailVerificationCode}. It expires in 10 minutes. If you didn't request this, you can ignore this message.`
50
50
  });
51
51
  } catch (err) {
52
- console.warn("failed to resend otp email", err);
52
+ console.error("failed to resend otp email", err);
53
+ try {
54
+ await User.updateOne({
55
+ _id: user._id,
56
+ emailVerificationCode
57
+ }, {
58
+ $unset: {
59
+ emailVerificationCode: "",
60
+ emailVerificationExpiresAt: ""
61
+ }
62
+ });
63
+ } catch (releaseErr) {
64
+ console.error("failed to clear unsent otp", releaseErr);
65
+ }
66
+ ctx.res.status(500);
67
+ return {
68
+ success: false,
69
+ error: "email_delivery_failed"
70
+ };
53
71
  }
54
72
  return {
55
73
  success: true
@@ -59,6 +77,7 @@ const handler = (api) => {
59
77
  api.post(Route, resendOtp);
60
78
  };
61
79
  export {
62
- handler as default
80
+ handler as default,
81
+ resendOtp
63
82
  };
64
- //# sourceMappingURL=handler-DG8GMWwR.js.map
83
+ //# sourceMappingURL=handler-BKSik1j0.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler-BKSik1j0.js","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 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 User = await models.getGlobal(\"RBUser\", ctx)\n\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 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"],"names":["Route","requestSchema","z","email","string","success","boolean","error","optional","resendOtp","payload","ctx","User","models","getGlobal","parsed","ResendOtp","safeParse","res","status","data","user","findOne","emailVerificationCode","crypto","randomInt","toString","padStart","emailVerificationExpiresAt","Date","now","save","sendEmail","to","subject","html","text","err","console","updateOne","_id","$unset","releaseErr","api","post"],"mappings":";;;;AAGO,MAAMA,QAAQ;AAEd,MAAMC,gBAAgBC,OAAS;AAAA,EACpCC,OAAOD,OAAEE,EAASD,MAAAA;AACpB,CAAC;AAI6BD,OAAS;AAAA,EACrCG,SAASH,QAAEI;AAAAA,EACXC,OAAOL,OAAEE,EAASI,SAAAA;AACpB,CAAC;ACHM,MAAMC,YAA8F,OACzGC,SACAC,QACuC;AACvC,QAAMC,OAAO,MAAMC,OAAOC,UAAU,UAAUH,GAAG;AAEjD,QAAMI,SAASC,cAAwBC,UAAUP,OAAO;AAExD,MAAI,CAACK,OAAOV,SAAS;AACnBM,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEd,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAM;AAAA,IAAEJ;AAAAA,EAAAA,IAAUY,OAAOK;AAEzB,QAAMC,OAAO,MAAMT,KAAKU,QAAQ;AAAA,IAAEnB;AAAAA,EAAAA,CAAO;AAEzC,MAAI,CAACkB,MAAM;AAETV,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEd,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAGA,QAAMgB,wBAAwBC,OAAOC,UAAU,GAAG,GAAS,EAAEC,WAAWC,SAAS,GAAG,GAAG;AACvF,QAAMC,6BAA6B,IAAIC,KAAKA,KAAKC,QAAQ,KAAK,KAAK,GAAI;AAEvET,OAAKE,wBAAwBA;AAC7BF,OAAKO,6BAA6BA;AAClC,QAAMP,KAAKU,KAAAA;AAEX,MAAI;AACF,UAAMC,UAAU;AAAA,MACdC,IAAI9B;AAAAA,MACJ+B,SAAS,2BAA2BX,qBAAqB;AAAA,MACzDY,MAAM;AAAA,+CACmCZ,qBAAqB;AAAA;AAAA;AAAA,MAG9Da,MAAM,6BAA6Bb,qBAAqB;AAAA,IAAA,CACzD;AAAA,EACH,SAASc,KAAK;AACZC,YAAQ/B,MAAM,8BAA8B8B,GAAG;AAE/C,QAAI;AACF,YAAMzB,KAAK2B,UACT;AAAA,QAAEC,KAAKnB,KAAKmB;AAAAA,QAAKjB;AAAAA,MAAAA,GACjB;AAAA,QACEkB,QAAQ;AAAA,UACNlB,uBAAuB;AAAA,UACvBK,4BAA4B;AAAA,QAAA;AAAA,MAC9B,CAEJ;AAAA,IACF,SAASc,YAAY;AACnBJ,cAAQ/B,MAAM,8BAA8BmC,UAAU;AAAA,IACxD;AAEA/B,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEd,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,SAAO;AAAA,IAAEF,SAAS;AAAA,EAAA;AACpB;AAEA,MAAA,UAAe,CAACsC,QAA8B;AAC5CA,MAAIC,KAAK5B,OAAiBP,SAAS;AACrC;"}
@@ -1,7 +1,7 @@
1
1
  import crypto from "crypto";
2
2
  import { models } from "@rpcbase/db";
3
3
  import { hashPasswordForStorage, sendEmail } from "@rpcbase/server";
4
- import { R as Route, r as requestSchema } from "./index-sfjvVpg9.js";
4
+ import { R as Route, r as requestSchema } from "./index-1_ZKABa_.js";
5
5
  const signUp = async (payload, ctx) => {
6
6
  const User = await models.getGlobal("RBUser", ctx);
7
7
  const Tenant = await models.getGlobal("RBTenant", ctx);
@@ -56,7 +56,19 @@ const signUp = async (payload, ctx) => {
56
56
  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.`
57
57
  });
58
58
  } catch (err) {
59
- console.warn("failed to send sign-up email", err);
59
+ console.error("failed to send sign-up email", err);
60
+ try {
61
+ await User.deleteOne({
62
+ _id: user._id
63
+ });
64
+ } catch (rollbackErr) {
65
+ console.error("failed to roll back user after sign-up email failure", rollbackErr);
66
+ }
67
+ ctx.res.status(500);
68
+ return {
69
+ success: false,
70
+ error: "email_delivery_failed"
71
+ };
60
72
  }
61
73
  try {
62
74
  await Tenant.create({
@@ -77,6 +89,7 @@ const handler = (api) => {
77
89
  api.post(Route, signUp);
78
90
  };
79
91
  export {
80
- handler as default
92
+ handler as default,
93
+ signUp
81
94
  };
82
- //# sourceMappingURL=handler-BlhyOTyk.js.map
95
+ //# sourceMappingURL=handler-BXvh_Nx4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler-BXvh_Nx4.js","sources":["../src/api/sign-up/handler.ts"],"sourcesContent":["import crypto from \"crypto\"\n\nimport { Api, Ctx, ApiHandler } from \"@rpcbase/api\"\nimport { models } from \"@rpcbase/db\"\nimport { hashPasswordForStorage, sendEmail } from \"@rpcbase/server\"\n\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 User = await models.getGlobal(\"RBUser\", ctx)\n const Tenant = await models.getGlobal(\"RBTenant\", ctx)\n\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 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 Tenant.create({\n tenantId,\n name: email,\n })\n } catch (err) {\n // best-effort tenant creation; log and continue\n console.warn(\"failed to create tenant for user\", err)\n }\n\n console.log(\"created new user\", user._id.toString())\n\n return { success: true, userId: user._id.toString(), tenantId }\n}\n\nexport default (api: Api<AuthSessionUser>) => {\n api.post(SignUp.Route, signUp)\n}\n"],"names":["signUp","payload","ctx","User","models","getGlobal","Tenant","parsed","SignUp","safeParse","success","res","status","error","email","password","rememberMe","_rememberMe","data","existingUser","findOne","console","log","hashedPassword","hashPasswordForStorage","tenantId","crypto","randomUUID","emailVerificationCode","randomInt","toString","padStart","emailVerificationExpiresAt","Date","now","user","tenants","tenantRoles","save","sendEmail","to","subject","html","text","err","deleteOne","_id","rollbackErr","create","name","warn","userId","api","post"],"mappings":";;;;AAWO,MAAMA,SAAqF,OAChGC,SACAC,QACoC;AACpC,QAAMC,OAAO,MAAMC,OAAOC,UAAU,UAAUH,GAAG;AACjD,QAAMI,SAAS,MAAMF,OAAOC,UAAU,YAAYH,GAAG;AAErD,QAAMK,SAASC,cAAqBC,UAAUR,OAAO;AAErD,MAAI,CAACM,OAAOG,SAAS;AACnBR,QAAIS,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEF,SAAS;AAAA,MAAOG,OAAO;AAAA,IAAA;AAAA,EAClC;AAGA,QAAM;AAAA,IAAEC;AAAAA,IAAOC;AAAAA,IAAUC,YAAYC;AAAAA,EAAAA,IAAgBV,OAAOW;AAE5D,QAAMC,eAAe,MAAMhB,KAAKiB,QAAQ;AAAA,IAAEN;AAAAA,EAAAA,CAAO;AAEjD,MAAIK,cAAc;AAChBE,YAAQC,IAAI,kCAAkCR,KAAK;AAGnDZ,QAAIS,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEF,SAAS;AAAA,MAAOG,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAMU,iBAAiB,MAAMC,uBAAuBT,QAAQ;AAE5D,QAAMU,WAAWC,OAAOC,WAAAA;AAExB,QAAMC,wBAAwBF,OAAOG,UAAU,GAAG,GAAS,EAAEC,WAAWC,SAAS,GAAG,GAAG;AACvF,QAAMC,6BAA6B,IAAIC,KAAKA,KAAKC,QAAQ,KAAK,KAAK,GAAI;AAEvE,QAAMC,OAAO,IAAIhC,KAAK;AAAA,IACpBW;AAAAA,IACAC,UAAUQ;AAAAA,IACVa,SAAS,CAACX,QAAQ;AAAA,IAClBY,aAAa;AAAA,MACX,CAACZ,QAAQ,GAAG,CAAC,OAAO;AAAA,IAAA;AAAA,IAEtBG;AAAAA,IACAI;AAAAA,EAAAA,CACD;AACD,QAAMG,KAAKG,KAAAA;AAEX,MAAI;AACF,UAAMC,UAAU;AAAA,MACdC,IAAI1B;AAAAA,MACJ2B,SAAS,sBAAsBb,qBAAqB;AAAA,MACpDc,MAAM;AAAA;AAAA,+CAEmCd,qBAAqB;AAAA;AAAA;AAAA,MAG9De,MAAM,iDAAiDf,qBAAqB;AAAA,IAAA,CAC7E;AAAA,EACH,SAASgB,KAAK;AACZvB,YAAQR,MAAM,gCAAgC+B,GAAG;AAEjD,QAAI;AACF,YAAMzC,KAAK0C,UAAU;AAAA,QAAEC,KAAKX,KAAKW;AAAAA,MAAAA,CAAK;AAAA,IACxC,SAASC,aAAa;AACpB1B,cAAQR,MAAM,wDAAwDkC,WAAW;AAAA,IACnF;AAEA7C,QAAIS,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEF,SAAS;AAAA,MAAOG,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,MAAI;AACF,UAAMP,OAAO0C,OAAO;AAAA,MAClBvB;AAAAA,MACAwB,MAAMnC;AAAAA,IAAAA,CACP;AAAA,EACH,SAAS8B,KAAK;AAEZvB,YAAQ6B,KAAK,oCAAoCN,GAAG;AAAA,EACtD;AAEAvB,UAAQC,IAAI,oBAAoBa,KAAKW,IAAIhB,UAAU;AAEnD,SAAO;AAAA,IAAEpB,SAAS;AAAA,IAAMyC,QAAQhB,KAAKW,IAAIhB,SAAAA;AAAAA,IAAYL;AAAAA,EAAAA;AACvD;AAEA,MAAA,UAAe,CAAC2B,QAA8B;AAC5CA,MAAIC,KAAK7C,OAAcR,MAAM;AAC/B;"}
@@ -1,6 +1,6 @@
1
1
  import { b as restrictSessionMiddleware } from "./middleware-8IfSkEEy.js";
2
2
  import { A as AUTHENTICATED_TENANT_ID_HEADER } from "./session-DoTNxRRA.js";
3
- import { o as object, s as string, b as boolean } from "./schemas-BYptELX5.js";
3
+ import { o as object, s as string, b as boolean } from "./schemas--f80aXK7.js";
4
4
  const Route = "/api/rb/auth/set-active-account";
5
5
  const requestSchema = object({
6
6
  tenantId: string().min(1, "Tenant is required")
@@ -63,4 +63,4 @@ const handler = (api) => {
63
63
  export {
64
64
  handler as default
65
65
  };
66
- //# sourceMappingURL=handler-BIFPHnwb.js.map
66
+ //# sourceMappingURL=handler-B_lItxOC.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"handler-BIFPHnwb.js","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"],"names":["Route","requestSchema","z","tenantId","string","min","success","boolean","error","optional","setActiveAccount","payload","ctx","parsed","SetActiveAccount","safeParse","res","status","sessionUser","req","session","user","id","data","trim","signedInTenants","Array","isArray","map","String","length","includes","currentTenantId","setHeader","AUTHENTICATED_TENANT_ID_HEADER","api","use","restrictSessionMiddleware","post"],"mappings":";;;AAGO,MAAMA,QAAQ;AAEd,MAAMC,gBAAgBC,OAAS;AAAA,EACpCC,UAAUD,OAAEE,EAASC,IAAI,GAAG,oBAAoB;AAClD,CAAC;AAI6BH,OAAS;AAAA,EACrCI,SAASJ,QAAEK;AAAAA,EACXC,OAAON,OAAEE,EAASK,SAAAA;AAAAA,EAClBN,UAAUD,OAAEE,EAASK,SAAAA;AACvB,CAAC;ACND,MAAMC,mBAIF,OACFC,SACAC,QAC8C;AAC9C,QAAMC,SAASC,cAA+BC,UAAUJ,OAAO;AAE/D,MAAI,CAACE,OAAOP,SAAS;AACnBM,QAAII,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEX,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAMU,cAAcN,IAAIO,IAAIC,SAASC;AACrC,MAAI,CAACH,aAAaI,IAAI;AACpBV,QAAII,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEX,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAML,WAAWU,OAAOU,KAAKpB,SAASqB,KAAAA;AACtC,QAAMC,kBAAkBC,MAAMC,QAAQT,YAAYO,eAAe,IAC7DP,YAAYO,gBAAgBG,IAAIC,MAAM,IACtC,CAAA;AAEJ,MAAIJ,gBAAgBK,SAAS,KAAK,CAACL,gBAAgBM,SAAS5B,QAAQ,GAAG;AACrES,QAAII,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEX,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,MAAIiB,gBAAgBK,WAAW,GAAG;AAChC,UAAME,kBAAkB,OAAOd,YAAYc,oBAAoB,WAAWd,YAAYc,gBAAgBR,SAAS;AAC/G,QAAI,CAACQ,mBAAmBA,oBAAoB7B,UAAU;AACpDS,UAAII,IAAIC,OAAO,GAAG;AAClB,aAAO;AAAA,QAAEX,SAAS;AAAA,QAAOE,OAAO;AAAA,MAAA;AAAA,IAClC;AAAA,EACF;AAEAI,MAAIO,IAAIC,QAAQC,OAAO;AAAA,IACrB,GAAGH;AAAAA,IACHc,iBAAiB7B;AAAAA,EAAAA;AAEnBS,MAAII,IAAIiB,UAAUC,gCAAgC/B,QAAQ;AAE1D,SAAO;AAAA,IAAEG,SAAS;AAAA,IAAMH;AAAAA,EAAAA;AAC1B;AAEA,MAAA,UAAe,CAACgC,QAA8B;AAC5CA,MAAIC,IAAItB,OAAwBuB,yBAAyB;AACzDF,MAAIG,KAAKxB,OAAwBJ,gBAAgB;AACnD;"}
1
+ {"version":3,"file":"handler-B_lItxOC.js","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"],"names":["Route","requestSchema","z","tenantId","string","min","success","boolean","error","optional","setActiveAccount","payload","ctx","parsed","SetActiveAccount","safeParse","res","status","sessionUser","req","session","user","id","data","trim","signedInTenants","Array","isArray","map","String","length","includes","currentTenantId","setHeader","AUTHENTICATED_TENANT_ID_HEADER","api","use","restrictSessionMiddleware","post"],"mappings":";;;AAGO,MAAMA,QAAQ;AAEd,MAAMC,gBAAgBC,OAAS;AAAA,EACpCC,UAAUD,OAAEE,EAASC,IAAI,GAAG,oBAAoB;AAClD,CAAC;AAI6BH,OAAS;AAAA,EACrCI,SAASJ,QAAEK;AAAAA,EACXC,OAAON,OAAEE,EAASK,SAAAA;AAAAA,EAClBN,UAAUD,OAAEE,EAASK,SAAAA;AACvB,CAAC;ACND,MAAMC,mBAIF,OACFC,SACAC,QAC8C;AAC9C,QAAMC,SAASC,cAA+BC,UAAUJ,OAAO;AAE/D,MAAI,CAACE,OAAOP,SAAS;AACnBM,QAAII,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEX,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAMU,cAAcN,IAAIO,IAAIC,SAASC;AACrC,MAAI,CAACH,aAAaI,IAAI;AACpBV,QAAII,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEX,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAML,WAAWU,OAAOU,KAAKpB,SAASqB,KAAAA;AACtC,QAAMC,kBAAkBC,MAAMC,QAAQT,YAAYO,eAAe,IAC7DP,YAAYO,gBAAgBG,IAAIC,MAAM,IACtC,CAAA;AAEJ,MAAIJ,gBAAgBK,SAAS,KAAK,CAACL,gBAAgBM,SAAS5B,QAAQ,GAAG;AACrES,QAAII,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEX,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,MAAIiB,gBAAgBK,WAAW,GAAG;AAChC,UAAME,kBAAkB,OAAOd,YAAYc,oBAAoB,WAAWd,YAAYc,gBAAgBR,SAAS;AAC/G,QAAI,CAACQ,mBAAmBA,oBAAoB7B,UAAU;AACpDS,UAAII,IAAIC,OAAO,GAAG;AAClB,aAAO;AAAA,QAAEX,SAAS;AAAA,QAAOE,OAAO;AAAA,MAAA;AAAA,IAClC;AAAA,EACF;AAEAI,MAAIO,IAAIC,QAAQC,OAAO;AAAA,IACrB,GAAGH;AAAAA,IACHc,iBAAiB7B;AAAAA,EAAAA;AAEnBS,MAAII,IAAIiB,UAAUC,gCAAgC/B,QAAQ;AAE1D,SAAO;AAAA,IAAEG,SAAS;AAAA,IAAMH;AAAAA,EAAAA;AAC1B;AAEA,MAAA,UAAe,CAACgC,QAA8B;AAC5CA,MAAIC,IAAItB,OAAwBuB,yBAAyB;AACzDF,MAAIG,KAAKxB,OAAwBJ,gBAAgB;AACnD;"}
@@ -1,4 +1,4 @@
1
- import { o as object, b as boolean } from "./schemas-BYptELX5.js";
1
+ import { o as object, b as boolean } from "./schemas--f80aXK7.js";
2
2
  const Route = "/api/rb/auth/sign-out";
3
3
  object({});
4
4
  object({
@@ -21,4 +21,4 @@ const handler = (api) => {
21
21
  export {
22
22
  handler as default
23
23
  };
24
- //# sourceMappingURL=handler-4-ccxPqk.js.map
24
+ //# sourceMappingURL=handler-BuwKXMOu.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"handler-4-ccxPqk.js","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"],"names":["Route","z","success","boolean","handleSignOut","_","ctx","req","session","Promise","resolve","destroy","api","post","SignOut"],"mappings":";AAGO,MAAMA,QAAQ;AAGQC,OAAS,CAAA,CAAE;AAIVA,OAAS;AAAA,EACrCC,SAASD,QAAEE;AACb,CAAC;ACPD,MAAMC,gBAAgB,OAAMC,GAA2BC,QAA+C;AAEpG,MAAI,CAACA,IAAIC,IAAIC,SAAS;AACpB,WAAO;AAAA,MAAEN,SAAS;AAAA,IAAA;AAAA,EACpB;AAEA,QAAM,IAAIO,QAAeC,CAAAA,YAAYJ,IAAIC,IAAIC,QAASG,QAAQ,MAAMD,QAAAA,CAAS,CAAC;AAE9E,SAAO;AAAA,IACLR,SAAS;AAAA,EAAA;AAEb;AAEA,MAAA,UAAe,CAACU,QAAa;AAC3BA,MAAIC,KAAKC,OAAeV,aAAa;AACvC;"}
1
+ {"version":3,"file":"handler-BuwKXMOu.js","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"],"names":["Route","z","success","boolean","handleSignOut","_","ctx","req","session","Promise","resolve","destroy","api","post","SignOut"],"mappings":";AAGO,MAAMA,QAAQ;AAGQC,OAAS,CAAA,CAAE;AAIVA,OAAS;AAAA,EACrCC,SAASD,QAAEE;AACb,CAAC;ACPD,MAAMC,gBAAgB,OAAMC,GAA2BC,QAA+C;AAEpG,MAAI,CAACA,IAAIC,IAAIC,SAAS;AACpB,WAAO;AAAA,MAAEN,SAAS;AAAA,IAAA;AAAA,EACpB;AAEA,QAAM,IAAIO,QAAeC,CAAAA,YAAYJ,IAAIC,IAAIC,QAASG,QAAQ,MAAMD,QAAAA,CAAS,CAAC;AAE9E,SAAO;AAAA,IACLR,SAAS;AAAA,EAAA;AAEb;AAEA,MAAA,UAAe,CAACU,QAAa;AAC3BA,MAAIC,KAAKC,OAAeV,aAAa;AACvC;"}
@@ -1,6 +1,6 @@
1
1
  import { models } from "@rpcbase/db";
2
2
  import { b as restrictSessionMiddleware } from "./middleware-8IfSkEEy.js";
3
- import { o as object, s as string, a as array } from "./schemas-BYptELX5.js";
3
+ import { o as object, s as string, a as array } from "./schemas--f80aXK7.js";
4
4
  const Route = "/api/rb/auth/me";
5
5
  object({});
6
6
  object({
@@ -65,4 +65,4 @@ const handler = (api) => {
65
65
  export {
66
66
  handler as default
67
67
  };
68
- //# sourceMappingURL=handler-BOCOLt9O.js.map
68
+ //# sourceMappingURL=handler-C-hPxnHG.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"handler-BOCOLt9O.js","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"],"names":["Route","z","id","string","optional","email","phone","name","tenants","default","currentTenantId","signedInTenants","error","me","_payload","ctx","sessionUser","req","session","user","res","status","User","models","getGlobal","findById","tenantId","trim","_id","toString","get","map","String","api","use","Me","restrictSessionMiddleware"],"mappings":";;;AAGO,MAAMA,QAAQ;AAEQC,OAAS,CAAA,CAAE;AAGVA,OAAS;AAAA,EACrCC,IAAID,OAAEE,EAASC,SAAAA;AAAAA,EACfC,OAAOJ,OAAEE,EAASE,MAAAA,EAAQD,SAAAA;AAAAA,EAC1BE,OAAOL,OAAEE,EAASC,SAAAA;AAAAA,EAClBG,MAAMN,OAAEE,EAASC,SAAAA;AAAAA,EACjBI,SAASP,MAAQA,QAAU,EAAEQ,QAAQ,CAAA,CAAE;AAAA,EACvCC,iBAAiBT,OAAEE,EAASC,SAAAA;AAAAA,EAC5BO,iBAAiBV,MAAQA,OAAEE,CAAQ,EAAEM,QAAQ,CAAA,CAAE,EAAEL,SAAAA;AAAAA,EACjDQ,OAAOX,OAAEE,EAASC,SAAAA;AACpB,CAAC;ACRD,MAAMS,KAAyE,OAC7EC,UACAC,QACgC;AAChC,QAAMC,cAAcD,IAAIE,IAAIC,SAASC;AAErC,MAAI,CAACH,aAAad,IAAI;AACpBa,QAAIK,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MACLnB,IAAI;AAAA,MACJQ,iBAAiB;AAAA,MACjBC,iBAAiB,CAAA;AAAA,MACjBH,SAAS,CAAA;AAAA,MACTI,OAAO;AAAA,IAAA;AAAA,EAEX;AAEA,QAAMU,OAAO,MAAMC,OAAOC,UAAU,UAAUT,GAAG;AACjD,QAAMI,OAAO,MAAMG,KAAKG,SAAST,YAAYd,EAAE;AAE/C,MAAI,CAACiB,MAAM;AACTJ,QAAIK,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MACLnB,IAAI;AAAA,MACJQ,iBAAiB;AAAA,MACjBC,iBAAiB,CAAA;AAAA,MACjBH,SAAS,CAAA;AAAA,MACTI,OAAO;AAAA,IAAA;AAAA,EAEX;AAEA,QAAMc,WAAW,OAAOV,YAAYN,oBAAoB,WAAWM,YAAYN,gBAAgBiB,SAAS;AACxG,MAAI,CAACD,UAAU;AACbX,QAAIK,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MACLnB,IAAI;AAAA,MACJQ,iBAAiB;AAAA,MACjBC,iBAAiB,CAAA;AAAA,MACjBH,SAAS,CAAA;AAAA,MACTI,OAAO;AAAA,IAAA;AAAA,EAEX;AAEA,SAAO;AAAA,IACLV,IAAIiB,KAAKS,IAAIC,SAAAA;AAAAA,IACbxB,OAAOc,KAAKd;AAAAA,IACZC,OAAOa,KAAKW,IAAI,OAAO;AAAA,IACvBvB,MAAMY,KAAKZ;AAAAA,IACXC,UAAUW,KAAKX,WAAW,CAAA,GAAIuB,IAAIC,MAAM;AAAA,IACxCtB,iBAAiBgB;AAAAA,IACjBf,iBAAiBK,YAAYL,mBAAmB,CAAA;AAAA,EAAA;AAEpD;AAEA,MAAA,UAAe,CAACsB,QAA8B;AAC5CA,MAAIC,IAAIC,OAAUC,yBAAyB;AAC3CH,MAAIH,IAAIK,OAAUtB,EAAE;AACtB;"}
1
+ {"version":3,"file":"handler-C-hPxnHG.js","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"],"names":["Route","z","id","string","optional","email","phone","name","tenants","default","currentTenantId","signedInTenants","error","me","_payload","ctx","sessionUser","req","session","user","res","status","User","models","getGlobal","findById","tenantId","trim","_id","toString","get","map","String","api","use","Me","restrictSessionMiddleware"],"mappings":";;;AAGO,MAAMA,QAAQ;AAEQC,OAAS,CAAA,CAAE;AAGVA,OAAS;AAAA,EACrCC,IAAID,OAAEE,EAASC,SAAAA;AAAAA,EACfC,OAAOJ,OAAEE,EAASE,MAAAA,EAAQD,SAAAA;AAAAA,EAC1BE,OAAOL,OAAEE,EAASC,SAAAA;AAAAA,EAClBG,MAAMN,OAAEE,EAASC,SAAAA;AAAAA,EACjBI,SAASP,MAAQA,QAAU,EAAEQ,QAAQ,CAAA,CAAE;AAAA,EACvCC,iBAAiBT,OAAEE,EAASC,SAAAA;AAAAA,EAC5BO,iBAAiBV,MAAQA,OAAEE,CAAQ,EAAEM,QAAQ,CAAA,CAAE,EAAEL,SAAAA;AAAAA,EACjDQ,OAAOX,OAAEE,EAASC,SAAAA;AACpB,CAAC;ACRD,MAAMS,KAAyE,OAC7EC,UACAC,QACgC;AAChC,QAAMC,cAAcD,IAAIE,IAAIC,SAASC;AAErC,MAAI,CAACH,aAAad,IAAI;AACpBa,QAAIK,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MACLnB,IAAI;AAAA,MACJQ,iBAAiB;AAAA,MACjBC,iBAAiB,CAAA;AAAA,MACjBH,SAAS,CAAA;AAAA,MACTI,OAAO;AAAA,IAAA;AAAA,EAEX;AAEA,QAAMU,OAAO,MAAMC,OAAOC,UAAU,UAAUT,GAAG;AACjD,QAAMI,OAAO,MAAMG,KAAKG,SAAST,YAAYd,EAAE;AAE/C,MAAI,CAACiB,MAAM;AACTJ,QAAIK,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MACLnB,IAAI;AAAA,MACJQ,iBAAiB;AAAA,MACjBC,iBAAiB,CAAA;AAAA,MACjBH,SAAS,CAAA;AAAA,MACTI,OAAO;AAAA,IAAA;AAAA,EAEX;AAEA,QAAMc,WAAW,OAAOV,YAAYN,oBAAoB,WAAWM,YAAYN,gBAAgBiB,SAAS;AACxG,MAAI,CAACD,UAAU;AACbX,QAAIK,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MACLnB,IAAI;AAAA,MACJQ,iBAAiB;AAAA,MACjBC,iBAAiB,CAAA;AAAA,MACjBH,SAAS,CAAA;AAAA,MACTI,OAAO;AAAA,IAAA;AAAA,EAEX;AAEA,SAAO;AAAA,IACLV,IAAIiB,KAAKS,IAAIC,SAAAA;AAAAA,IACbxB,OAAOc,KAAKd;AAAAA,IACZC,OAAOa,KAAKW,IAAI,OAAO;AAAA,IACvBvB,MAAMY,KAAKZ;AAAAA,IACXC,UAAUW,KAAKX,WAAW,CAAA,GAAIuB,IAAIC,MAAM;AAAA,IACxCtB,iBAAiBgB;AAAAA,IACjBf,iBAAiBK,YAAYL,mBAAmB,CAAA;AAAA,EAAA;AAEpD;AAEA,MAAA,UAAe,CAACsB,QAA8B;AAC5CA,MAAIC,IAAIC,OAAUC,yBAAyB;AAC3CH,MAAIH,IAAIK,OAAUtB,EAAE;AACtB;"}
@@ -1,7 +1,7 @@
1
1
  import { models } from "@rpcbase/db";
2
2
  import { verifyPasswordFromStorage } from "@rpcbase/server";
3
3
  import { c as completeAuthSignIn } from "./session-DoTNxRRA.js";
4
- import { R as Route, r as requestSchema } from "./index-DznfuMJi.js";
4
+ import { R as Route, r as requestSchema } from "./index-D94-1Zwh.js";
5
5
  const signIn = async (payload, ctx) => {
6
6
  const User = await models.getGlobal("RBUser", ctx);
7
7
  const parsed = requestSchema.safeParse(payload);
@@ -78,4 +78,4 @@ const handler = (api) => {
78
78
  export {
79
79
  handler as default
80
80
  };
81
- //# sourceMappingURL=handler-Y6JMPCW0.js.map
81
+ //# sourceMappingURL=handler-CoHpAhui.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"handler-Y6JMPCW0.js","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"],"names":["signIn","payload","ctx","User","models","getGlobal","parsed","SignIn","safeParse","success","res","status","error","email","password","data","user","findOne","tenants","tenantRoles","stored","String","passwordMatches","verifyPasswordFromStorage","startsWith","console","warn","_id","toString","signedInTenants","map","defaultTenantId","tenantId","tenantRolesMap","get","Object","fromEntries","entries","undefined","completeAuthSignIn","userId","currentTenantId","length","api","post"],"mappings":";;;;AAUA,MAAMA,SAAqF,OACzFC,SACAC,QACoC;AACpC,QAAMC,OAAO,MAAMC,OAAOC,UAAU,UAAUH,GAAG;AAEjD,QAAMI,SAASC,cAAqBC,UAAUP,OAAO;AAErD,MAAI,CAACK,OAAOG,SAAS;AACnBP,QAAIQ,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEF,SAAS;AAAA,MAAOG,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAM;AAAA,IAAEC;AAAAA,IAAOC;AAAAA,EAAAA,IAAaR,OAAOS;AAEnC,QAAMC,OAAO,MAAMb,KAAKc,QAAQ;AAAA,IAAEJ;AAAAA,EAAAA,GAAS;AAAA,IAAEC,UAAU;AAAA,IAAGI,SAAS;AAAA,IAAGC,aAAa;AAAA,EAAA,CAAG;AAEtF,MAAI,CAACH,MAAMF,UAAU;AACnBZ,QAAIQ,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEF,SAAS;AAAA,MAAOG,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAMQ,SAASC,OAAOL,KAAKF,QAAQ;AACnC,QAAMQ,kBAAkB,MAAMC,0BAA0BT,UAAUM,MAAM;AAExE,MAAI,CAACE,iBAAiB;AACpB,QAAI,CAACF,OAAOI,WAAW,UAAU,GAAG;AAClCC,cAAQC,KAAK,gDAAgDV,KAAKW,IAAIC,UAAU;AAAA,IAClF;AACA1B,QAAIQ,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEF,SAAS;AAAA,MAAOG,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAMiB,mBAAmBb,KAAKE,WAAW,CAAA,GAAIY,IAAIT,MAAM;AACvD,QAAMU,kBAAkBF,gBAAgB,CAAC;AACzC,MAAI,CAACE,iBAAiB;AACpB7B,QAAIQ,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEF,SAAS;AAAA,MAAOG,OAAO;AAAA,IAAA;AAAA,EAClC;AACA,QAAMoB,WAAWD;AACjB,QAAME,iBAAiBjB,KAAKkB,IAAI,aAAa;AAC7C,QAAMf,cAAcc,iBAAiBE,OAAOC,YAAYH,eAAeI,QAAAA,CAAS,IAAIC;AAEpF,MAAI,CAACC,mBAAmBrC,KAAK;AAAA,IAC3BsC,QAAQxB,KAAKW,IAAIC,SAAAA;AAAAA,IACjBa,iBAAiBT;AAAAA,IACjBH,iBAAiBA,gBAAgBa,SAASb,kBAAkB,CAACG,QAAQ;AAAA,IACrEb;AAAAA,EAAAA,CACD,GAAG;AACFjB,QAAIQ,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEF,SAAS;AAAA,MAAOG,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,SAAO;AAAA,IAAEH,SAAS;AAAA,IAAM+B,QAAQxB,KAAKW,IAAIC,SAAAA;AAAAA,IAAYI;AAAAA,EAAAA;AACvD;AAEA,MAAA,UAAe,CAACW,QAA8B;AAC5CA,MAAIC,KAAKrC,OAAcP,MAAM;AAC/B;"}
1
+ {"version":3,"file":"handler-CoHpAhui.js","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"],"names":["signIn","payload","ctx","User","models","getGlobal","parsed","SignIn","safeParse","success","res","status","error","email","password","data","user","findOne","tenants","tenantRoles","stored","String","passwordMatches","verifyPasswordFromStorage","startsWith","console","warn","_id","toString","signedInTenants","map","defaultTenantId","tenantId","tenantRolesMap","get","Object","fromEntries","entries","undefined","completeAuthSignIn","userId","currentTenantId","length","api","post"],"mappings":";;;;AAUA,MAAMA,SAAqF,OACzFC,SACAC,QACoC;AACpC,QAAMC,OAAO,MAAMC,OAAOC,UAAU,UAAUH,GAAG;AAEjD,QAAMI,SAASC,cAAqBC,UAAUP,OAAO;AAErD,MAAI,CAACK,OAAOG,SAAS;AACnBP,QAAIQ,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEF,SAAS;AAAA,MAAOG,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAM;AAAA,IAAEC;AAAAA,IAAOC;AAAAA,EAAAA,IAAaR,OAAOS;AAEnC,QAAMC,OAAO,MAAMb,KAAKc,QAAQ;AAAA,IAAEJ;AAAAA,EAAAA,GAAS;AAAA,IAAEC,UAAU;AAAA,IAAGI,SAAS;AAAA,IAAGC,aAAa;AAAA,EAAA,CAAG;AAEtF,MAAI,CAACH,MAAMF,UAAU;AACnBZ,QAAIQ,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEF,SAAS;AAAA,MAAOG,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAMQ,SAASC,OAAOL,KAAKF,QAAQ;AACnC,QAAMQ,kBAAkB,MAAMC,0BAA0BT,UAAUM,MAAM;AAExE,MAAI,CAACE,iBAAiB;AACpB,QAAI,CAACF,OAAOI,WAAW,UAAU,GAAG;AAClCC,cAAQC,KAAK,gDAAgDV,KAAKW,IAAIC,UAAU;AAAA,IAClF;AACA1B,QAAIQ,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEF,SAAS;AAAA,MAAOG,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAMiB,mBAAmBb,KAAKE,WAAW,CAAA,GAAIY,IAAIT,MAAM;AACvD,QAAMU,kBAAkBF,gBAAgB,CAAC;AACzC,MAAI,CAACE,iBAAiB;AACpB7B,QAAIQ,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEF,SAAS;AAAA,MAAOG,OAAO;AAAA,IAAA;AAAA,EAClC;AACA,QAAMoB,WAAWD;AACjB,QAAME,iBAAiBjB,KAAKkB,IAAI,aAAa;AAC7C,QAAMf,cAAcc,iBAAiBE,OAAOC,YAAYH,eAAeI,QAAAA,CAAS,IAAIC;AAEpF,MAAI,CAACC,mBAAmBrC,KAAK;AAAA,IAC3BsC,QAAQxB,KAAKW,IAAIC,SAAAA;AAAAA,IACjBa,iBAAiBT;AAAAA,IACjBH,iBAAiBA,gBAAgBa,SAASb,kBAAkB,CAACG,QAAQ;AAAA,IACrEb;AAAAA,EAAAA,CACD,GAAG;AACFjB,QAAIQ,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEF,SAAS;AAAA,MAAOG,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,SAAO;AAAA,IAAEH,SAAS;AAAA,IAAM+B,QAAQxB,KAAKW,IAAIC,SAAAA;AAAAA,IAAYI;AAAAA,EAAAA;AACvD;AAEA,MAAA,UAAe,CAACW,QAA8B;AAC5CA,MAAIC,KAAKrC,OAAcP,MAAM;AAC/B;"}
@@ -1,6 +1,6 @@
1
1
  import { models } from "@rpcbase/db";
2
2
  import { c as completeAuthSignIn } from "./session-DoTNxRRA.js";
3
- import { o as object, b as boolean, s as string } from "./schemas-BYptELX5.js";
3
+ import { o as object, b as boolean, s as string } from "./schemas--f80aXK7.js";
4
4
  const Route = "/api/rb/auth/verify-otp";
5
5
  const requestSchema = object({
6
6
  email: string().email(),
@@ -91,4 +91,4 @@ const handler = (api) => {
91
91
  export {
92
92
  handler as default
93
93
  };
94
- //# sourceMappingURL=handler-BvztD8II.js.map
94
+ //# sourceMappingURL=handler-DfZwgoA4.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"handler-BvztD8II.js","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"],"names":["Route","requestSchema","z","email","string","code","length","rememberMe","default","success","boolean","error","optional","userId","tenantId","verifyOtp","payload","ctx","User","models","getGlobal","parsed","VerifyOtp","safeParse","res","status","data","user","findOne","emailVerificationCode","emailVerificationExpiresAt","tenants","tenantRoles","storedCode","expiresAt","isExpired","Date","getTime","now","undefined","save","signedInTenants","map","String","defaultTenantId","tenantRolesMap","get","Object","fromEntries","entries","completeAuthSignIn","_id","toString","currentTenantId","api","post"],"mappings":";;;AAGO,MAAMA,QAAQ;AAEd,MAAMC,gBAAgBC,OAAS;AAAA,EACpCC,OAAOD,OAAEE,EAASD,MAAAA;AAAAA,EAClBE,MAAMH,OAAEE,EAASE,OAAO,GAAG,uBAAuB;AAAA,EAClDC,YAAYL,UAAYM,QAAQ,IAAI;AACtC,CAAC;AAI6BN,OAAS;AAAA,EACrCO,SAASP,QAAEQ;AAAAA,EACXC,OAAOT,OAAEE,EAASQ,SAAAA;AAAAA,EAClBC,QAAQX,OAAEE,EAASQ,SAAAA;AAAAA,EACnBE,UAAUZ,OAAEE,EAASQ,SAAAA;AACvB,CAAC;ACTD,MAAMG,YAA8F,OAClGC,SACAC,QACuC;AACvC,QAAMC,OAAO,MAAMC,OAAOC,UAAU,UAAUH,GAAG;AAEjD,QAAMI,SAASC,cAAwBC,UAAUP,OAAO;AAExD,MAAI,CAACK,OAAOZ,SAAS;AACnBQ,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEhB,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAM;AAAA,IAAER;AAAAA,IAAOE;AAAAA,EAAAA,IAASgB,OAAOK;AAE/B,QAAMC,OAAO,MAAMT,KAAKU,QAAQ;AAAA,IAAEzB;AAAAA,EAAAA,GAAS;AAAA,IAAE0B,uBAAuB;AAAA,IAAGC,4BAA4B;AAAA,IAAGC,SAAS;AAAA,IAAGC,aAAa;AAAA,EAAA,CAAG;AAElI,MAAI,CAACL,MAAM;AACTV,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEhB,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAMsB,aAAaN,KAAKE;AACxB,QAAMK,YAAYP,KAAKG;AAEvB,QAAMK,YAAYD,qBAAqBE,QAAQF,UAAUG,QAAAA,IAAYD,KAAKE,IAAAA;AAC1E,MAAI,CAACL,cAAcA,eAAe5B,QAAQ8B,WAAW;AACnDlB,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEhB,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEAgB,OAAKE,wBAAwBU;AAC7BZ,OAAKG,6BAA6BS;AAClC,QAAMZ,KAAKa,KAAAA;AAEX,QAAMC,mBAAmBd,KAAKI,WAAW,CAAA,GAAIW,IAAIC,MAAM;AACvD,QAAMC,kBAAkBH,gBAAgB,CAAC;AACzC,MAAI,CAACG,iBAAiB;AACpB3B,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEhB,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AACA,QAAMG,WAAW8B;AACjB,QAAMC,iBAAiBlB,KAAKmB,IAAI,aAAa;AAC7C,QAAMd,cAAca,iBAAiBE,OAAOC,YAAYH,eAAeI,QAAAA,CAAS,IAAIV;AAEpF,MAAI,CAACW,mBAAmBjC,KAAK;AAAA,IAC3BJ,QAAQc,KAAKwB,IAAIC,SAAAA;AAAAA,IACjBC,iBAAiBvC;AAAAA,IACjB2B,iBAAiBA,gBAAgBnC,SAASmC,kBAAkB,CAAC3B,QAAQ;AAAA,IACrEkB;AAAAA,EAAAA,CACD,GAAG;AACFf,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEhB,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,SAAO;AAAA,IAAEF,SAAS;AAAA,IAAMI,QAAQc,KAAKwB,IAAIC,SAAAA;AAAAA,IAAYtC;AAAAA,EAAAA;AACvD;AAEA,MAAA,UAAe,CAACwC,QAA8B;AAC5CA,MAAIC,KAAKjC,OAAiBP,SAAS;AACrC;"}
1
+ {"version":3,"file":"handler-DfZwgoA4.js","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"],"names":["Route","requestSchema","z","email","string","code","length","rememberMe","default","success","boolean","error","optional","userId","tenantId","verifyOtp","payload","ctx","User","models","getGlobal","parsed","VerifyOtp","safeParse","res","status","data","user","findOne","emailVerificationCode","emailVerificationExpiresAt","tenants","tenantRoles","storedCode","expiresAt","isExpired","Date","getTime","now","undefined","save","signedInTenants","map","String","defaultTenantId","tenantRolesMap","get","Object","fromEntries","entries","completeAuthSignIn","_id","toString","currentTenantId","api","post"],"mappings":";;;AAGO,MAAMA,QAAQ;AAEd,MAAMC,gBAAgBC,OAAS;AAAA,EACpCC,OAAOD,OAAEE,EAASD,MAAAA;AAAAA,EAClBE,MAAMH,OAAEE,EAASE,OAAO,GAAG,uBAAuB;AAAA,EAClDC,YAAYL,UAAYM,QAAQ,IAAI;AACtC,CAAC;AAI6BN,OAAS;AAAA,EACrCO,SAASP,QAAEQ;AAAAA,EACXC,OAAOT,OAAEE,EAASQ,SAAAA;AAAAA,EAClBC,QAAQX,OAAEE,EAASQ,SAAAA;AAAAA,EACnBE,UAAUZ,OAAEE,EAASQ,SAAAA;AACvB,CAAC;ACTD,MAAMG,YAA8F,OAClGC,SACAC,QACuC;AACvC,QAAMC,OAAO,MAAMC,OAAOC,UAAU,UAAUH,GAAG;AAEjD,QAAMI,SAASC,cAAwBC,UAAUP,OAAO;AAExD,MAAI,CAACK,OAAOZ,SAAS;AACnBQ,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEhB,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAM;AAAA,IAAER;AAAAA,IAAOE;AAAAA,EAAAA,IAASgB,OAAOK;AAE/B,QAAMC,OAAO,MAAMT,KAAKU,QAAQ;AAAA,IAAEzB;AAAAA,EAAAA,GAAS;AAAA,IAAE0B,uBAAuB;AAAA,IAAGC,4BAA4B;AAAA,IAAGC,SAAS;AAAA,IAAGC,aAAa;AAAA,EAAA,CAAG;AAElI,MAAI,CAACL,MAAM;AACTV,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEhB,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAMsB,aAAaN,KAAKE;AACxB,QAAMK,YAAYP,KAAKG;AAEvB,QAAMK,YAAYD,qBAAqBE,QAAQF,UAAUG,QAAAA,IAAYD,KAAKE,IAAAA;AAC1E,MAAI,CAACL,cAAcA,eAAe5B,QAAQ8B,WAAW;AACnDlB,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEhB,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEAgB,OAAKE,wBAAwBU;AAC7BZ,OAAKG,6BAA6BS;AAClC,QAAMZ,KAAKa,KAAAA;AAEX,QAAMC,mBAAmBd,KAAKI,WAAW,CAAA,GAAIW,IAAIC,MAAM;AACvD,QAAMC,kBAAkBH,gBAAgB,CAAC;AACzC,MAAI,CAACG,iBAAiB;AACpB3B,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEhB,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AACA,QAAMG,WAAW8B;AACjB,QAAMC,iBAAiBlB,KAAKmB,IAAI,aAAa;AAC7C,QAAMd,cAAca,iBAAiBE,OAAOC,YAAYH,eAAeI,QAAAA,CAAS,IAAIV;AAEpF,MAAI,CAACW,mBAAmBjC,KAAK;AAAA,IAC3BJ,QAAQc,KAAKwB,IAAIC,SAAAA;AAAAA,IACjBC,iBAAiBvC;AAAAA,IACjB2B,iBAAiBA,gBAAgBnC,SAASmC,kBAAkB,CAAC3B,QAAQ;AAAA,IACrEkB;AAAAA,EAAAA,CACD,GAAG;AACFf,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEhB,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,SAAO;AAAA,IAAEF,SAAS;AAAA,IAAMI,QAAQc,KAAKwB,IAAIC,SAAAA;AAAAA,IAAYtC;AAAAA,EAAAA;AACvD;AAEA,MAAA,UAAe,CAACwC,QAA8B;AAC5CA,MAAIC,KAAKjC,OAAiBP,SAAS;AACrC;"}
@@ -1,6 +1,6 @@
1
1
  import crypto from "crypto";
2
2
  import { models } from "@rpcbase/db";
3
- import { o as object, s as string, b as boolean } from "./schemas-BYptELX5.js";
3
+ import { o as object, s as string, b as boolean } from "./schemas--f80aXK7.js";
4
4
  const Route = "/api/rb/auth/verify-password-reset-otp";
5
5
  const requestSchema = object({
6
6
  email: string().email(),
@@ -55,4 +55,4 @@ const handler = (api) => {
55
55
  export {
56
56
  handler as default
57
57
  };
58
- //# sourceMappingURL=handler-Dbkf3cD8.js.map
58
+ //# sourceMappingURL=handler-Eyjkxj9l.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"handler-Dbkf3cD8.js","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"],"names":["Route","requestSchema","z","email","string","code","length","success","boolean","error","optional","resetToken","verifyPasswordResetOtp","payload","ctx","User","models","getGlobal","parsed","VerifyPasswordResetOtp","safeParse","res","status","data","user","findOne","storedCode","passwordResetCode","expiresAt","passwordResetCodeExpiresAt","isExpired","Date","getTime","now","crypto","randomBytes","toString","undefined","passwordResetToken","passwordResetTokenExpiresAt","save","api","post"],"mappings":";;;AAGO,MAAMA,QAAQ;AAEd,MAAMC,gBAAgBC,OAAS;AAAA,EACpCC,OAAOD,OAAEE,EAASD,MAAAA;AAAAA,EAClBE,MAAMH,OAAEE,EAASE,OAAO,GAAG,uBAAuB;AACpD,CAAC;AAI6BJ,OAAS;AAAA,EACrCK,SAASL,QAAEM;AAAAA,EACXC,OAAOP,OAAEE,EAASM,SAAAA;AAAAA,EAClBC,YAAYT,OAAEE,EAASM,SAAAA;AACzB,CAAC;ACND,MAAME,yBAIF,OACFC,SACAC,QACoD;AACpD,QAAMC,OAAO,MAAMC,OAAOC,UAAU,UAAUH,GAAG;AAEjD,QAAMI,SAASC,cAAqCC,UAAUP,OAAO;AAErE,MAAI,CAACK,OAAOX,SAAS;AACnBO,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEf,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAM;AAAA,IAAEN;AAAAA,IAAOE;AAAAA,EAAAA,IAASa,OAAOK;AAC/B,QAAMC,OAAO,MAAMT,KAAKU,QAAQ;AAAA,IAAEtB;AAAAA,EAAAA,CAAO;AAEzC,QAAMuB,aAAaF,MAAMG;AACzB,QAAMC,YAAYJ,MAAMK;AACxB,QAAMC,YAAYF,qBAAqBG,QAAQH,UAAUI,QAAAA,IAAYD,KAAKE,IAAAA;AAE1E,MAAI,CAACT,QAAQ,CAACE,cAAcA,eAAerB,QAAQyB,WAAW;AAC5DhB,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEf,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAME,aAAauB,OAAOC,YAAY,EAAE,EAAEC,SAAS,KAAK;AAExDZ,OAAKG,oBAAoBU;AACzBb,OAAKK,6BAA6BQ;AAClCb,OAAKc,qBAAqB3B;AAC1Ba,OAAKe,8BAA8B,IAAIR,KAAKA,KAAKE,QAAQ,KAAK,KAAK,GAAI;AACvE,QAAMT,KAAKgB,KAAAA;AAEX,SAAO;AAAA,IAAEjC,SAAS;AAAA,IAAMI;AAAAA,EAAAA;AAC1B;AAEA,MAAA,UAAe,CAAC8B,QAA8B;AAC5CA,MAAIC,KAAKvB,OAA8BP,sBAAsB;AAC/D;"}
1
+ {"version":3,"file":"handler-Eyjkxj9l.js","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"],"names":["Route","requestSchema","z","email","string","code","length","success","boolean","error","optional","resetToken","verifyPasswordResetOtp","payload","ctx","User","models","getGlobal","parsed","VerifyPasswordResetOtp","safeParse","res","status","data","user","findOne","storedCode","passwordResetCode","expiresAt","passwordResetCodeExpiresAt","isExpired","Date","getTime","now","crypto","randomBytes","toString","undefined","passwordResetToken","passwordResetTokenExpiresAt","save","api","post"],"mappings":";;;AAGO,MAAMA,QAAQ;AAEd,MAAMC,gBAAgBC,OAAS;AAAA,EACpCC,OAAOD,OAAEE,EAASD,MAAAA;AAAAA,EAClBE,MAAMH,OAAEE,EAASE,OAAO,GAAG,uBAAuB;AACpD,CAAC;AAI6BJ,OAAS;AAAA,EACrCK,SAASL,QAAEM;AAAAA,EACXC,OAAOP,OAAEE,EAASM,SAAAA;AAAAA,EAClBC,YAAYT,OAAEE,EAASM,SAAAA;AACzB,CAAC;ACND,MAAME,yBAIF,OACFC,SACAC,QACoD;AACpD,QAAMC,OAAO,MAAMC,OAAOC,UAAU,UAAUH,GAAG;AAEjD,QAAMI,SAASC,cAAqCC,UAAUP,OAAO;AAErE,MAAI,CAACK,OAAOX,SAAS;AACnBO,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEf,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAM;AAAA,IAAEN;AAAAA,IAAOE;AAAAA,EAAAA,IAASa,OAAOK;AAC/B,QAAMC,OAAO,MAAMT,KAAKU,QAAQ;AAAA,IAAEtB;AAAAA,EAAAA,CAAO;AAEzC,QAAMuB,aAAaF,MAAMG;AACzB,QAAMC,YAAYJ,MAAMK;AACxB,QAAMC,YAAYF,qBAAqBG,QAAQH,UAAUI,QAAAA,IAAYD,KAAKE,IAAAA;AAE1E,MAAI,CAACT,QAAQ,CAACE,cAAcA,eAAerB,QAAQyB,WAAW;AAC5DhB,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEf,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAME,aAAauB,OAAOC,YAAY,EAAE,EAAEC,SAAS,KAAK;AAExDZ,OAAKG,oBAAoBU;AACzBb,OAAKK,6BAA6BQ;AAClCb,OAAKc,qBAAqB3B;AAC1Ba,OAAKe,8BAA8B,IAAIR,KAAKA,KAAKE,QAAQ,KAAK,KAAK,GAAI;AACvE,QAAMT,KAAKgB,KAAAA;AAEX,SAAO;AAAA,IAAEjC,SAAS;AAAA,IAAMI;AAAAA,EAAAA;AAC1B;AAEA,MAAA,UAAe,CAAC8B,QAA8B;AAC5CA,MAAIC,KAAKvB,OAA8BP,sBAAsB;AAC/D;"}
@@ -1,6 +1,6 @@
1
1
  import { models } from "@rpcbase/db";
2
2
  import { hashPasswordForStorage } from "@rpcbase/server";
3
- import { o as object, s as string, b as boolean } from "./schemas-BYptELX5.js";
3
+ import { o as object, s as string, b as boolean } from "./schemas--f80aXK7.js";
4
4
  const Route = "/api/rb/auth/set-new-password";
5
5
  const requestSchema = object({
6
6
  email: string().email(),
@@ -56,4 +56,4 @@ const handler = (api) => {
56
56
  export {
57
57
  handler as default
58
58
  };
59
- //# sourceMappingURL=handler-EYTkh4N4.js.map
59
+ //# sourceMappingURL=handler-U3df_2Al.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"handler-EYTkh4N4.js","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"],"names":["Route","requestSchema","z","email","string","resetToken","min","password","message","success","boolean","error","optional","setNewPassword","payload","ctx","User","models","getGlobal","parsed","SetNewPassword","safeParse","res","status","data","user","findOne","storedToken","passwordResetToken","tokenExpiresAt","passwordResetTokenExpiresAt","isExpired","Date","getTime","now","hashedPassword","hashPasswordForStorage","undefined","save","api","post"],"mappings":";;;AAGO,MAAMA,QAAQ;AAEd,MAAMC,gBAAgBC,OAAS;AAAA,EACpCC,OAAOD,OAAEE,EAASD,MAAAA;AAAAA,EAClBE,YAAYH,OAAEE,EAASE,IAAI,CAAC;AAAA,EAC5BC,UAAUL,OAAEE,EAASE,IAAI,GAAG;AAAA,IAAEE,SAAS;AAAA,EAAA,CAAgD;AACzF,CAAC;AAI6BN,OAAS;AAAA,EACrCO,SAASP,QAAEQ;AAAAA,EACXC,OAAOT,OAAEE,EAASQ,SAAAA;AACpB,CAAC;ACPD,MAAMC,iBAIF,OACFC,SACAC,QAC4C;AAC5C,QAAMC,OAAO,MAAMC,OAAOC,UAAU,UAAUH,GAAG;AAEjD,QAAMI,SAASC,cAA6BC,UAAUP,OAAO;AAE7D,MAAI,CAACK,OAAOV,SAAS;AACnBM,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEd,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAM;AAAA,IAAER;AAAAA,IAAOE;AAAAA,IAAYE;AAAAA,EAAAA,IAAaY,OAAOK;AAE/C,QAAMC,OAAO,MAAMT,KAAKU,QAAQ;AAAA,IAAEvB;AAAAA,EAAAA,CAAO;AACzC,QAAMwB,cAAcF,MAAMG;AAC1B,QAAMC,iBAAiBJ,MAAMK;AAC7B,QAAMC,YAAYF,0BAA0BG,QAAQH,eAAeI,QAAAA,IAAYD,KAAKE,IAAAA;AAEpF,MAAI,CAACT,QAAQ,CAACE,eAAeA,gBAAgBtB,cAAc0B,WAAW;AACpEhB,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEd,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAMwB,iBAAiB,MAAMC,uBAAuB7B,QAAQ;AAC5DkB,OAAKlB,WAAW4B;AAChBV,OAAKG,qBAAqBS;AAC1BZ,OAAKK,8BAA8BO;AACnC,QAAMZ,KAAKa,KAAAA;AAEX,SAAO;AAAA,IAAE7B,SAAS;AAAA,EAAA;AACpB;AAEA,MAAA,UAAe,CAAC8B,QAA8B;AAC5CA,MAAIC,KAAKpB,OAAsBP,cAAc;AAC/C;"}
1
+ {"version":3,"file":"handler-U3df_2Al.js","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"],"names":["Route","requestSchema","z","email","string","resetToken","min","password","message","success","boolean","error","optional","setNewPassword","payload","ctx","User","models","getGlobal","parsed","SetNewPassword","safeParse","res","status","data","user","findOne","storedToken","passwordResetToken","tokenExpiresAt","passwordResetTokenExpiresAt","isExpired","Date","getTime","now","hashedPassword","hashPasswordForStorage","undefined","save","api","post"],"mappings":";;;AAGO,MAAMA,QAAQ;AAEd,MAAMC,gBAAgBC,OAAS;AAAA,EACpCC,OAAOD,OAAEE,EAASD,MAAAA;AAAAA,EAClBE,YAAYH,OAAEE,EAASE,IAAI,CAAC;AAAA,EAC5BC,UAAUL,OAAEE,EAASE,IAAI,GAAG;AAAA,IAAEE,SAAS;AAAA,EAAA,CAAgD;AACzF,CAAC;AAI6BN,OAAS;AAAA,EACrCO,SAASP,QAAEQ;AAAAA,EACXC,OAAOT,OAAEE,EAASQ,SAAAA;AACpB,CAAC;ACPD,MAAMC,iBAIF,OACFC,SACAC,QAC4C;AAC5C,QAAMC,OAAO,MAAMC,OAAOC,UAAU,UAAUH,GAAG;AAEjD,QAAMI,SAASC,cAA6BC,UAAUP,OAAO;AAE7D,MAAI,CAACK,OAAOV,SAAS;AACnBM,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEd,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAM;AAAA,IAAER;AAAAA,IAAOE;AAAAA,IAAYE;AAAAA,EAAAA,IAAaY,OAAOK;AAE/C,QAAMC,OAAO,MAAMT,KAAKU,QAAQ;AAAA,IAAEvB;AAAAA,EAAAA,CAAO;AACzC,QAAMwB,cAAcF,MAAMG;AAC1B,QAAMC,iBAAiBJ,MAAMK;AAC7B,QAAMC,YAAYF,0BAA0BG,QAAQH,eAAeI,QAAAA,IAAYD,KAAKE,IAAAA;AAEpF,MAAI,CAACT,QAAQ,CAACE,eAAeA,gBAAgBtB,cAAc0B,WAAW;AACpEhB,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEd,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAMwB,iBAAiB,MAAMC,uBAAuB7B,QAAQ;AAC5DkB,OAAKlB,WAAW4B;AAChBV,OAAKG,qBAAqBS;AAC1BZ,OAAKK,8BAA8BO;AACnC,QAAMZ,KAAKa,KAAAA;AAEX,SAAO;AAAA,IAAE7B,SAAS;AAAA,EAAA;AACpB;AAEA,MAAA,UAAe,CAAC8B,QAA8B;AAC5CA,MAAIC,KAAKpB,OAAsBP,cAAc;AAC/C;"}