@rpcbase/auth 0.109.0 → 0.111.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 (59) hide show
  1. package/dist/handler-BH38xcvj.js +60 -0
  2. package/dist/handler-BH38xcvj.js.map +1 -0
  3. package/dist/handler-Bjxe8iM2.js +67 -0
  4. package/dist/handler-Bjxe8iM2.js.map +1 -0
  5. package/dist/handler-CVeU9Nyf.js +85 -0
  6. package/dist/handler-CVeU9Nyf.js.map +1 -0
  7. package/dist/handler-CrTy-N1A.js +51 -0
  8. package/dist/handler-CrTy-N1A.js.map +1 -0
  9. package/dist/handler-D2-FmmDc.js +56 -0
  10. package/dist/handler-D2-FmmDc.js.map +1 -0
  11. package/dist/handler-D4-sXlBe.js +74 -0
  12. package/dist/handler-D4-sXlBe.js.map +1 -0
  13. package/dist/handler-D87G4mz9.js +67 -0
  14. package/dist/handler-D87G4mz9.js.map +1 -0
  15. package/dist/handler-DKrwSIQz.js +19 -0
  16. package/dist/handler-DKrwSIQz.js.map +1 -0
  17. package/dist/handler-tJUJWqII.js +59 -0
  18. package/dist/handler-tJUJWqII.js.map +1 -0
  19. package/dist/index.js +657 -684
  20. package/dist/index.js.map +1 -1
  21. package/dist/middleware-BbKZ_rOe.js +18 -0
  22. package/dist/middleware-BbKZ_rOe.js.map +1 -0
  23. package/dist/oauth/index.js +625 -746
  24. package/dist/oauth/index.js.map +1 -1
  25. package/dist/routes.js +18 -9
  26. package/dist/routes.js.map +1 -1
  27. package/dist/schemas-BKnjeqQ9.js +3380 -0
  28. package/dist/schemas-BKnjeqQ9.js.map +1 -0
  29. package/dist/sign-in-C9a-NvBu.js +18 -0
  30. package/dist/sign-in-C9a-NvBu.js.map +1 -0
  31. package/dist/sign-up-DqDJxb2D.js +18 -0
  32. package/dist/sign-up-DqDJxb2D.js.map +1 -0
  33. package/package.json +1 -1
  34. package/dist/handler-BNDemOGd.js +0 -79
  35. package/dist/handler-BNDemOGd.js.map +0 -1
  36. package/dist/handler-Bt53h0sk.js +0 -64
  37. package/dist/handler-Bt53h0sk.js.map +0 -1
  38. package/dist/handler-C4cw739Z.js +0 -59
  39. package/dist/handler-C4cw739Z.js.map +0 -1
  40. package/dist/handler-Ck7oLQ_R.js +0 -87
  41. package/dist/handler-Ck7oLQ_R.js.map +0 -1
  42. package/dist/handler-CyP6R8FM.js +0 -24
  43. package/dist/handler-CyP6R8FM.js.map +0 -1
  44. package/dist/handler-D6zJn86A.js +0 -82
  45. package/dist/handler-D6zJn86A.js.map +0 -1
  46. package/dist/handler-D8HfTbUs.js +0 -58
  47. package/dist/handler-D8HfTbUs.js.map +0 -1
  48. package/dist/handler-DfEsSB4T.js +0 -74
  49. package/dist/handler-DfEsSB4T.js.map +0 -1
  50. package/dist/handler-xEpHnzkZ.js +0 -58
  51. package/dist/handler-xEpHnzkZ.js.map +0 -1
  52. package/dist/index-Bxz6YdiB.js +0 -20
  53. package/dist/index-Bxz6YdiB.js.map +0 -1
  54. package/dist/index-C_uBu_fP.js +0 -20
  55. package/dist/index-C_uBu_fP.js.map +0 -1
  56. package/dist/middleware-5Zwy7HRL.js +0 -25
  57. package/dist/middleware-5Zwy7HRL.js.map +0 -1
  58. package/dist/schemas-Dn3gHDGz.js +0 -3706
  59. package/dist/schemas-Dn3gHDGz.js.map +0 -1
@@ -0,0 +1,18 @@
1
+ import { i as string, n as boolean, r as object } from "./schemas-BKnjeqQ9.js";
2
+ //#region src/api/sign-in/index.ts
3
+ var Route = "/api/rb/auth/sign-in";
4
+ var requestSchema = object({
5
+ email: string().nonempty("Email is required").email("Please enter a valid email address"),
6
+ password: string().min(1, { message: "Password is required" }),
7
+ rememberMe: boolean().default(true)
8
+ });
9
+ object({
10
+ success: boolean(),
11
+ error: string().optional(),
12
+ userId: string().optional(),
13
+ tenantId: string().optional()
14
+ });
15
+ //#endregion
16
+ export { requestSchema as n, Route as t };
17
+
18
+ //# sourceMappingURL=sign-in-C9a-NvBu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sign-in-C9a-NvBu.js","names":["z","Route","requestSchema","object","email","string","nonempty","password","min","message","rememberMe","boolean","default","RequestPayload","infer","responseSchema","success","error","optional","userId","tenantId","ResponsePayload"],"sources":["../src/api/sign-in/index.ts"],"sourcesContent":["import { z } from \"zod\"\n\n\nexport const Route = \"/api/rb/auth/sign-in\"\n\nexport const requestSchema = z.object({\n email: z\n .string()\n .nonempty(\"Email is required\")\n .email(\"Please enter a valid email address\"),\n password: z.string().min(1, { message: \"Password is required\" }),\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"],"mappings":";;AAGA,IAAaC,QAAQ;AAErB,IAAaC,gBAAgBF,OAAS;CACpCI,OAAOJ,QACI,CACRM,SAAS,oBAAoB,CAC7BF,MAAM,qCAAqC;CAC9CG,UAAUP,QAAU,CAACQ,IAAI,GAAG,EAAEC,SAAS,wBAAwB,CAAC;CAChEC,YAAYV,SAAW,CAACY,QAAQ,KAAI;CACrC,CAAC;AAI4BZ,OAAS;CACrCgB,SAAShB,SAAW;CACpBiB,OAAOjB,QAAU,CAACkB,UAAU;CAC5BC,QAAQnB,QAAU,CAACkB,UAAU;CAC7BE,UAAUpB,QAAU,CAACkB,UAAS;CAC/B,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { i as string, n as boolean, r as object } from "./schemas-BKnjeqQ9.js";
2
+ //#region src/api/sign-up/index.ts
3
+ var Route = "/api/rb/auth/sign-up";
4
+ var requestSchema = object({
5
+ email: string().nonempty("Email is required").email("Please enter a valid email address"),
6
+ password: string().min(8, { message: "Password must be at least 8 characters long." }),
7
+ rememberMe: boolean().default(true)
8
+ });
9
+ object({
10
+ success: boolean(),
11
+ error: string().optional(),
12
+ userId: string().optional(),
13
+ tenantId: string().optional()
14
+ });
15
+ //#endregion
16
+ export { requestSchema as n, Route as t };
17
+
18
+ //# sourceMappingURL=sign-up-DqDJxb2D.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sign-up-DqDJxb2D.js","names":["z","Route","requestSchema","object","email","string","nonempty","password","min","message","rememberMe","boolean","default","RequestPayload","infer","responseSchema","success","error","optional","userId","tenantId","ResponsePayload"],"sources":["../src/api/sign-up/index.ts"],"sourcesContent":["import { z } from \"zod\"\n\n\nexport const Route = \"/api/rb/auth/sign-up\"\n\nexport const requestSchema = z\n .object({\n email: z\n .string()\n .nonempty(\"Email is required\")\n .email(\"Please enter a valid email address\"),\n password: z.string().min(8, { message: \"Password must be at least 8 characters long.\" }),\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"],"mappings":";;AAGA,IAAaC,QAAQ;AAErB,IAAaC,gBAAgBF,OACnB;CACNI,OAAOJ,QACI,CACRM,SAAS,oBAAoB,CAC7BF,MAAM,qCAAqC;CAC9CG,UAAUP,QAAU,CAACQ,IAAI,GAAG,EAAEC,SAAS,gDAAgD,CAAC;CACxFC,YAAYV,SAAW,CAACY,QAAQ,KAAI;CACrC,CAAC;AAI0BZ,OAAS;CACrCgB,SAAShB,SAAW;CACpBiB,OAAOjB,QAAU,CAACkB,UAAU;CAC5BC,QAAQnB,QAAU,CAACkB,UAAU;CAC7BE,UAAUpB,QAAU,CAACkB,UAAS;CAC/B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpcbase/auth",
3
- "version": "0.109.0",
3
+ "version": "0.111.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -1,79 +0,0 @@
1
- import crypto from "crypto";
2
- import { models } from "@rpcbase/db";
3
- import { sendEmail } from "@rpcbase/server";
4
- import { o as object, s as string, b as boolean } from "./schemas-Dn3gHDGz.js";
5
- const Route = "/api/rb/auth/request-password-reset";
6
- const requestSchema = object({
7
- email: string().email()
8
- });
9
- object({
10
- success: boolean(),
11
- error: string().optional()
12
- });
13
- const maskEmailForLog = (email) => {
14
- const [localRaw, domainRaw = ""] = email.split("@");
15
- const local = localRaw || "";
16
- const domain = domainRaw || "";
17
- const localPrefix = local.slice(0, Math.min(3, local.length));
18
- const localMask = "*".repeat(Math.max(5, local.length - localPrefix.length));
19
- if (!domain) {
20
- return `${localPrefix}${localMask}@****`;
21
- }
22
- const domainTailLength = Math.min(7, domain.length);
23
- const domainTail = domain.slice(-domainTailLength);
24
- const domainMask = "*".repeat(Math.max(4, domain.length - domainTailLength));
25
- return `${localPrefix}${localMask}@${domainMask}${domainTail}`;
26
- };
27
- const requestPasswordReset = async (payload, ctx) => {
28
- const User = await models.getGlobal("RBUser", ctx);
29
- const parsed = requestSchema.safeParse(payload);
30
- if (!parsed.success) {
31
- ctx.res.status(400);
32
- return {
33
- success: false,
34
- error: "invalid_payload"
35
- };
36
- }
37
- const {
38
- email
39
- } = parsed.data;
40
- const user = await User.findOne({
41
- email
42
- });
43
- if (!user) {
44
- return {
45
- success: true
46
- };
47
- }
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
- try {
56
- console.info(`sending password reset to email ${maskEmailForLog(email)}`);
57
- await sendEmail({
58
- to: email,
59
- subject: `Your password reset code: ${passwordResetCode}`,
60
- html: `
61
- <p>Your password reset code is <strong>${passwordResetCode}</strong>. It expires in 10 minutes.</p>
62
- <p>If you didn't request this, you can ignore this message.</p>
63
- `,
64
- text: `Your password reset code is ${passwordResetCode}. It expires in 10 minutes. If you didn't request this, you can ignore this message.`
65
- });
66
- } catch (err) {
67
- console.warn("failed to send password reset email", err);
68
- }
69
- return {
70
- success: true
71
- };
72
- };
73
- const handler = (api) => {
74
- api.post(Route, requestPasswordReset);
75
- };
76
- export {
77
- handler as default
78
- };
79
- //# sourceMappingURL=handler-BNDemOGd.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"handler-BNDemOGd.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})\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\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\nconst 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 user = await User.findOne({ email })\n\n if (!user) {\n return { success: true }\n }\n\n const passwordResetCode = crypto.randomInt(0, 1_000_000).toString().padStart(6, \"0\")\n const passwordResetCodeExpiresAt = new Date(Date.now() + 10 * 60 * 1000)\n\n user.passwordResetCode = passwordResetCode\n user.passwordResetCodeExpiresAt = passwordResetCodeExpiresAt\n user.passwordResetToken = undefined\n user.passwordResetTokenExpiresAt = undefined\n await user.save()\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.warn(\"failed to send password reset email\", err)\n }\n\n return { success: true }\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","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","user","findOne","passwordResetCode","crypto","randomInt","toString","padStart","passwordResetCodeExpiresAt","Date","now","passwordResetToken","undefined","passwordResetTokenExpiresAt","save","console","info","sendEmail","to","subject","html","text","err","warn","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;ACHD,MAAMC,kBAAkBA,CAACN,UAAkB;AACzC,QAAM,CAACO,UAAUC,YAAY,EAAE,IAAIR,MAAMS,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;AAGA,MAAME,uBAIF,OACFC,SACAC,QACkD;AAClD,QAAMC,OAAO,MAAMC,OAAOC,UAAU,UAAUH,GAAG;AAEjD,QAAMI,SAASC,cAAmCC,UAAUP,OAAO;AAEnE,MAAI,CAACK,OAAO3B,SAAS;AACnBuB,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAE/B,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEA,QAAM;AAAA,IAAEJ;AAAAA,EAAAA,IAAU6B,OAAOK;AACzB,QAAMC,OAAO,MAAMT,KAAKU,QAAQ;AAAA,IAAEpC;AAAAA,EAAAA,CAAO;AAEzC,MAAI,CAACmC,MAAM;AACT,WAAO;AAAA,MAAEjC,SAAS;AAAA,IAAA;AAAA,EACpB;AAEA,QAAMmC,oBAAoBC,OAAOC,UAAU,GAAG,GAAS,EAAEC,WAAWC,SAAS,GAAG,GAAG;AACnF,QAAMC,6BAA6B,IAAIC,KAAKA,KAAKC,QAAQ,KAAK,KAAK,GAAI;AAEvET,OAAKE,oBAAoBA;AACzBF,OAAKO,6BAA6BA;AAClCP,OAAKU,qBAAqBC;AAC1BX,OAAKY,8BAA8BD;AACnC,QAAMX,KAAKa,KAAAA;AAEX,MAAI;AACFC,YAAQC,KAAK,mCAAmC5C,gBAAgBN,KAAK,CAAC,EAAE;AACxE,UAAMmD,UAAU;AAAA,MACdC,IAAIpD;AAAAA,MACJqD,SAAS,6BAA6BhB,iBAAiB;AAAA,MACvDiB,MAAM;AAAA,iDACqCjB,iBAAiB;AAAA;AAAA;AAAA,MAG5DkB,MAAM,+BAA+BlB,iBAAiB;AAAA,IAAA,CACvD;AAAA,EACH,SAASmB,KAAK;AACZP,YAAQQ,KAAK,uCAAuCD,GAAG;AAAA,EACzD;AAEA,SAAO;AAAA,IAAEtD,SAAS;AAAA,EAAA;AACpB;AAEA,MAAA,UAAe,CAACwD,QAA8B;AAC5CA,MAAIC,KAAK7B,OAA4BP,oBAAoB;AAC3D;"}
@@ -1,64 +0,0 @@
1
- import crypto from "crypto";
2
- import { models } from "@rpcbase/db";
3
- import { sendEmail } from "@rpcbase/server";
4
- import { o as object, s as string, b as boolean } from "./schemas-Dn3gHDGz.js";
5
- const Route = "/api/rb/auth/resend-otp";
6
- const requestSchema = object({
7
- email: string().email()
8
- });
9
- object({
10
- success: boolean(),
11
- error: string().optional()
12
- });
13
- const resendOtp = async (payload, ctx) => {
14
- const User = await models.getGlobal("RBUser", ctx);
15
- const parsed = requestSchema.safeParse(payload);
16
- if (!parsed.success) {
17
- ctx.res.status(400);
18
- return {
19
- success: false,
20
- error: "invalid_payload"
21
- };
22
- }
23
- const {
24
- email
25
- } = parsed.data;
26
- const user = await User.findOne({
27
- email
28
- });
29
- if (!user) {
30
- ctx.res.status(404);
31
- return {
32
- success: false,
33
- error: "user_not_found"
34
- };
35
- }
36
- const emailVerificationCode = crypto.randomInt(0, 1e6).toString().padStart(6, "0");
37
- const emailVerificationExpiresAt = new Date(Date.now() + 10 * 60 * 1e3);
38
- user.emailVerificationCode = emailVerificationCode;
39
- user.emailVerificationExpiresAt = emailVerificationExpiresAt;
40
- await user.save();
41
- try {
42
- await sendEmail({
43
- to: email,
44
- subject: `Your verification code: ${emailVerificationCode}`,
45
- html: `
46
- <p>Your verification code is <strong>${emailVerificationCode}</strong>. It expires in 10 minutes.</p>
47
- <p>If you didn't request this, you can ignore this message.</p>
48
- `,
49
- text: `Your verification code is ${emailVerificationCode}. It expires in 10 minutes. If you didn't request this, you can ignore this message.`
50
- });
51
- } catch (err) {
52
- console.warn("failed to resend otp email", err);
53
- }
54
- return {
55
- success: true
56
- };
57
- };
58
- const handler = (api) => {
59
- api.post(Route, resendOtp);
60
- };
61
- export {
62
- handler as default
63
- };
64
- //# sourceMappingURL=handler-Bt53h0sk.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"handler-Bt53h0sk.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\nconst 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.warn(\"failed to resend otp email\", err)\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","warn","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;ACHD,MAAMC,YAA8F,OAClGC,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,YAAQC,KAAK,8BAA8BF,GAAG;AAAA,EAChD;AAEA,SAAO;AAAA,IAAEhC,SAAS;AAAA,EAAA;AACpB;AAEA,MAAA,UAAe,CAACmC,QAA8B;AAC5CA,MAAIC,KAAKzB,OAAiBP,SAAS;AACrC;"}
@@ -1,59 +0,0 @@
1
- import { models } from "@rpcbase/db";
2
- import { hashPasswordForStorage } from "@rpcbase/server";
3
- import { o as object, s as string, b as boolean } from "./schemas-Dn3gHDGz.js";
4
- const Route = "/api/rb/auth/set-new-password";
5
- const requestSchema = object({
6
- email: string().email(),
7
- resetToken: string().min(1),
8
- password: string().min(8, {
9
- message: "Password must be at least 8 characters long."
10
- })
11
- });
12
- object({
13
- success: boolean(),
14
- error: string().optional()
15
- });
16
- const setNewPassword = async (payload, ctx) => {
17
- const User = await models.getGlobal("RBUser", ctx);
18
- const parsed = requestSchema.safeParse(payload);
19
- if (!parsed.success) {
20
- ctx.res.status(400);
21
- return {
22
- success: false,
23
- error: "invalid_payload"
24
- };
25
- }
26
- const {
27
- email,
28
- resetToken,
29
- password
30
- } = parsed.data;
31
- const user = await User.findOne({
32
- email
33
- });
34
- const storedToken = user?.passwordResetToken;
35
- const tokenExpiresAt = user?.passwordResetTokenExpiresAt;
36
- const isExpired = tokenExpiresAt instanceof Date && tokenExpiresAt.getTime() < Date.now();
37
- if (!user || !storedToken || storedToken !== resetToken || isExpired) {
38
- ctx.res.status(400);
39
- return {
40
- success: false,
41
- error: "invalid_token"
42
- };
43
- }
44
- const hashedPassword = await hashPasswordForStorage(password);
45
- user.password = hashedPassword;
46
- user.passwordResetToken = void 0;
47
- user.passwordResetTokenExpiresAt = void 0;
48
- await user.save();
49
- return {
50
- success: true
51
- };
52
- };
53
- const handler = (api) => {
54
- api.post(Route, setNewPassword);
55
- };
56
- export {
57
- handler as default
58
- };
59
- //# sourceMappingURL=handler-C4cw739Z.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"handler-C4cw739Z.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,87 +0,0 @@
1
- import { models } from "@rpcbase/db";
2
- import { o as object, b as boolean, s as string } from "./schemas-Dn3gHDGz.js";
3
- const Route = "/api/rb/auth/verify-otp";
4
- const requestSchema = object({
5
- email: string().email(),
6
- code: string().length(6, "Code must be 6 digits"),
7
- rememberMe: boolean().default(true)
8
- });
9
- object({
10
- success: boolean(),
11
- error: string().optional(),
12
- userId: string().optional(),
13
- tenantId: string().optional()
14
- });
15
- const verifyOtp = async (payload, ctx) => {
16
- const User = await models.getGlobal("RBUser", ctx);
17
- const parsed = requestSchema.safeParse(payload);
18
- if (!parsed.success) {
19
- ctx.res.status(400);
20
- return {
21
- success: false,
22
- error: "invalid_payload"
23
- };
24
- }
25
- const {
26
- email,
27
- code
28
- } = parsed.data;
29
- const user = await User.findOne({
30
- email
31
- }, {
32
- emailVerificationCode: 1,
33
- emailVerificationExpiresAt: 1,
34
- tenants: 1,
35
- tenantRoles: 1
36
- });
37
- if (!user) {
38
- ctx.res.status(404);
39
- return {
40
- success: false,
41
- error: "user_not_found"
42
- };
43
- }
44
- const storedCode = user.emailVerificationCode;
45
- const expiresAt = user.emailVerificationExpiresAt;
46
- const isExpired = expiresAt instanceof Date && expiresAt.getTime() < Date.now();
47
- if (!storedCode || storedCode !== code || isExpired) {
48
- ctx.res.status(400);
49
- return {
50
- success: false,
51
- error: "invalid_code"
52
- };
53
- }
54
- user.emailVerificationCode = void 0;
55
- user.emailVerificationExpiresAt = void 0;
56
- await user.save();
57
- const tenantId = user.tenants?.[0]?.toString?.() || "00000000";
58
- const signedInTenants = (user.tenants || []).map(String);
59
- const tenantRolesMap = user.get("tenantRoles");
60
- const tenantRoles = tenantRolesMap ? Object.fromEntries(tenantRolesMap.entries()) : void 0;
61
- if (!ctx.req.session) {
62
- ctx.res.status(500);
63
- return {
64
- success: false,
65
- error: "session_unavailable"
66
- };
67
- }
68
- ctx.req.session.user = {
69
- id: user._id.toString(),
70
- currentTenantId: tenantId,
71
- signedInTenants: signedInTenants.length ? signedInTenants : [tenantId],
72
- isEntryGateAuthorized: true,
73
- tenantRoles
74
- };
75
- return {
76
- success: true,
77
- userId: user._id.toString(),
78
- tenantId
79
- };
80
- };
81
- const handler = (api) => {
82
- api.post(Route, verifyOtp);
83
- };
84
- export {
85
- handler as default
86
- };
87
- //# sourceMappingURL=handler-Ck7oLQ_R.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"handler-Ck7oLQ_R.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 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 tenantId = user.tenants?.[0]?.toString?.() || \"00000000\"\n const signedInTenants = (user.tenants || []).map(String)\n const tenantRolesMap = user.get(\"tenantRoles\") as Map<string, string[]> | undefined\n const tenantRoles = tenantRolesMap ? Object.fromEntries(tenantRolesMap.entries()) : undefined\n\n if (!ctx.req.session) {\n ctx.res.status(500)\n return { success: false, error: \"session_unavailable\" }\n }\n\n ctx.req.session.user = {\n id: user._id.toString(),\n currentTenantId: tenantId,\n signedInTenants: signedInTenants.length ? signedInTenants : [tenantId],\n isEntryGateAuthorized: true,\n tenantRoles,\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","toString","signedInTenants","map","String","tenantRolesMap","get","Object","fromEntries","entries","req","session","id","_id","currentTenantId","isEntryGateAuthorized","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;ACVD,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,QAAM1B,WAAWa,KAAKI,UAAU,CAAC,GAAGU,gBAAgB;AACpD,QAAMC,mBAAmBf,KAAKI,WAAW,CAAA,GAAIY,IAAIC,MAAM;AACvD,QAAMC,iBAAiBlB,KAAKmB,IAAI,aAAa;AAC7C,QAAMd,cAAca,iBAAiBE,OAAOC,YAAYH,eAAeI,QAAAA,CAAS,IAAIV;AAEpF,MAAI,CAACtB,IAAIiC,IAAIC,SAAS;AACpBlC,QAAIO,IAAIC,OAAO,GAAG;AAClB,WAAO;AAAA,MAAEhB,SAAS;AAAA,MAAOE,OAAO;AAAA,IAAA;AAAA,EAClC;AAEAM,MAAIiC,IAAIC,QAAQxB,OAAO;AAAA,IACrByB,IAAIzB,KAAK0B,IAAIZ,SAAAA;AAAAA,IACba,iBAAiBxC;AAAAA,IACjB4B,iBAAiBA,gBAAgBpC,SAASoC,kBAAkB,CAAC5B,QAAQ;AAAA,IACrEyC,uBAAuB;AAAA,IACvBvB;AAAAA,EAAAA;AAGF,SAAO;AAAA,IAAEvB,SAAS;AAAA,IAAMI,QAAQc,KAAK0B,IAAIZ,SAAAA;AAAAA,IAAY3B;AAAAA,EAAAA;AACvD;AAEA,MAAA,UAAe,CAAC0C,QAA8B;AAC5CA,MAAIC,KAAKnC,OAAiBP,SAAS;AACrC;"}
@@ -1,24 +0,0 @@
1
- import { o as object, b as boolean } from "./schemas-Dn3gHDGz.js";
2
- const Route = "/api/rb/auth/sign-out";
3
- object({});
4
- object({
5
- success: boolean()
6
- });
7
- const handleSignOut = async (_, ctx) => {
8
- if (!ctx.req.session) {
9
- return {
10
- success: true
11
- };
12
- }
13
- await new Promise((resolve) => ctx.req.session.destroy(() => resolve()));
14
- return {
15
- success: true
16
- };
17
- };
18
- const handler = (api) => {
19
- api.post(Route, handleSignOut);
20
- };
21
- export {
22
- handler as default
23
- };
24
- //# sourceMappingURL=handler-CyP6R8FM.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"handler-CyP6R8FM.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,82 +0,0 @@
1
- import crypto from "crypto";
2
- import { models } from "@rpcbase/db";
3
- import { hashPasswordForStorage, sendEmail } from "@rpcbase/server";
4
- import { R as Route, r as requestSchema } from "./index-C_uBu_fP.js";
5
- const signUp = async (payload, ctx) => {
6
- const User = await models.getGlobal("RBUser", ctx);
7
- const Tenant = await models.getGlobal("RBTenant", ctx);
8
- const parsed = requestSchema.safeParse(payload);
9
- if (!parsed.success) {
10
- ctx.res.status(400);
11
- return {
12
- success: false,
13
- error: "invalid_payload"
14
- };
15
- }
16
- const {
17
- email,
18
- password,
19
- rememberMe: _rememberMe
20
- } = parsed.data;
21
- const existingUser = await User.findOne({
22
- email
23
- });
24
- if (existingUser) {
25
- console.log("user with email already exists", email);
26
- ctx.res.status(409);
27
- return {
28
- success: false,
29
- error: "user_exists"
30
- };
31
- }
32
- const hashedPassword = await hashPasswordForStorage(password);
33
- const tenantId = crypto.randomUUID();
34
- const emailVerificationCode = crypto.randomInt(0, 1e6).toString().padStart(6, "0");
35
- const emailVerificationExpiresAt = new Date(Date.now() + 10 * 60 * 1e3);
36
- const user = new User({
37
- email,
38
- password: hashedPassword,
39
- tenants: [tenantId],
40
- tenantRoles: {
41
- [tenantId]: ["owner"]
42
- },
43
- emailVerificationCode,
44
- emailVerificationExpiresAt
45
- });
46
- await user.save();
47
- try {
48
- await sendEmail({
49
- to: email,
50
- subject: `Verify your email: ${emailVerificationCode}`,
51
- html: `
52
- <p>Welcome to rpcbase!</p>
53
- <p>Your verification code is <strong>${emailVerificationCode}</strong>. It expires in 10 minutes.</p>
54
- <p>If you didn't request this, you can ignore this message.</p>
55
- `,
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
- });
58
- } catch (err) {
59
- console.warn("failed to send sign-up email", err);
60
- }
61
- try {
62
- await Tenant.create({
63
- tenantId,
64
- name: email
65
- });
66
- } catch (err) {
67
- console.warn("failed to create tenant for user", err);
68
- }
69
- console.log("created new user", user._id.toString());
70
- return {
71
- success: true,
72
- userId: user._id.toString(),
73
- tenantId
74
- };
75
- };
76
- const handler = (api) => {
77
- api.post(Route, signUp);
78
- };
79
- export {
80
- handler as default
81
- };
82
- //# sourceMappingURL=handler-D6zJn86A.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"handler-D6zJn86A.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\nconst 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.warn(\"failed to send sign-up email\", err)\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","warn","create","name","_id","userId","api","post"],"mappings":";;;;AAWA,MAAMA,SAAqF,OACzFC,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,YAAQwB,KAAK,gCAAgCD,GAAG;AAAA,EAClD;AAEA,MAAI;AACF,UAAMtC,OAAOwC,OAAO;AAAA,MAClBrB;AAAAA,MACAsB,MAAMjC;AAAAA,IAAAA,CACP;AAAA,EACH,SAAS8B,KAAK;AAEZvB,YAAQwB,KAAK,oCAAoCD,GAAG;AAAA,EACtD;AAEAvB,UAAQC,IAAI,oBAAoBa,KAAKa,IAAIlB,UAAU;AAEnD,SAAO;AAAA,IAAEpB,SAAS;AAAA,IAAMuC,QAAQd,KAAKa,IAAIlB,SAAAA;AAAAA,IAAYL;AAAAA,EAAAA;AACvD;AAEA,MAAA,UAAe,CAACyB,QAA8B;AAC5CA,MAAIC,KAAK3C,OAAcR,MAAM;AAC/B;"}
@@ -1,58 +0,0 @@
1
- import crypto from "crypto";
2
- import { models } from "@rpcbase/db";
3
- import { o as object, s as string, b as boolean } from "./schemas-Dn3gHDGz.js";
4
- const Route = "/api/rb/auth/verify-password-reset-otp";
5
- const requestSchema = object({
6
- email: string().email(),
7
- code: string().length(6, "Code must be 6 digits")
8
- });
9
- object({
10
- success: boolean(),
11
- error: string().optional(),
12
- resetToken: string().optional()
13
- });
14
- const verifyPasswordResetOtp = async (payload, ctx) => {
15
- const User = await models.getGlobal("RBUser", ctx);
16
- const parsed = requestSchema.safeParse(payload);
17
- if (!parsed.success) {
18
- ctx.res.status(400);
19
- return {
20
- success: false,
21
- error: "invalid_payload"
22
- };
23
- }
24
- const {
25
- email,
26
- code
27
- } = parsed.data;
28
- const user = await User.findOne({
29
- email
30
- });
31
- const storedCode = user?.passwordResetCode;
32
- const expiresAt = user?.passwordResetCodeExpiresAt;
33
- const isExpired = expiresAt instanceof Date && expiresAt.getTime() < Date.now();
34
- if (!user || !storedCode || storedCode !== code || isExpired) {
35
- ctx.res.status(400);
36
- return {
37
- success: false,
38
- error: "invalid_code"
39
- };
40
- }
41
- const resetToken = crypto.randomBytes(24).toString("hex");
42
- user.passwordResetCode = void 0;
43
- user.passwordResetCodeExpiresAt = void 0;
44
- user.passwordResetToken = resetToken;
45
- user.passwordResetTokenExpiresAt = new Date(Date.now() + 15 * 60 * 1e3);
46
- await user.save();
47
- return {
48
- success: true,
49
- resetToken
50
- };
51
- };
52
- const handler = (api) => {
53
- api.post(Route, verifyPasswordResetOtp);
54
- };
55
- export {
56
- handler as default
57
- };
58
- //# sourceMappingURL=handler-D8HfTbUs.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"handler-D8HfTbUs.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;"}