@rpcbase/auth 0.165.0 → 0.167.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 (66) hide show
  1. package/dist/handler-0nKR-P5B.js +84 -0
  2. package/dist/handler-0nKR-P5B.js.map +1 -0
  3. package/dist/handler-B8jPw9zh.js +74 -0
  4. package/dist/handler-B8jPw9zh.js.map +1 -0
  5. package/dist/handler-BGNM_dz1.js +19 -0
  6. package/dist/handler-BGNM_dz1.js.map +1 -0
  7. package/dist/handler-BoWTfKWi.js +56 -0
  8. package/dist/handler-BoWTfKWi.js.map +1 -0
  9. package/dist/handler-ClyVm_Us.js +92 -0
  10. package/dist/handler-ClyVm_Us.js.map +1 -0
  11. package/dist/handler-DNxEmrtP.js +67 -0
  12. package/dist/{handler-B_lItxOC.js.map → handler-DNxEmrtP.js.map} +1 -1
  13. package/dist/handler-DsPS6JXV.js +70 -0
  14. package/dist/handler-DsPS6JXV.js.map +1 -0
  15. package/dist/handler-GKdEwnBO.js +75 -0
  16. package/dist/handler-GKdEwnBO.js.map +1 -0
  17. package/dist/handler-IBGVDW5w.js +125 -0
  18. package/dist/handler-IBGVDW5w.js.map +1 -0
  19. package/dist/handler-J2OwFTyf.js +51 -0
  20. package/dist/handler-J2OwFTyf.js.map +1 -0
  21. package/dist/index.js +770 -756
  22. package/dist/index.js.map +1 -1
  23. package/dist/middleware-BT3Uput1.js +18 -0
  24. package/dist/middleware-BT3Uput1.js.map +1 -0
  25. package/dist/oauth/index.js +636 -761
  26. package/dist/oauth/index.js.map +1 -1
  27. package/dist/routes.js +19 -9
  28. package/dist/routes.js.map +1 -1
  29. package/dist/schemas-BgOpQqUv.js +3988 -0
  30. package/dist/schemas-BgOpQqUv.js.map +1 -0
  31. package/dist/session-BQ06Yo3C.js +20 -0
  32. package/dist/session-BQ06Yo3C.js.map +1 -0
  33. package/dist/sign-in-BG2ND3cO.js +18 -0
  34. package/dist/sign-in-BG2ND3cO.js.map +1 -0
  35. package/dist/sign-up-BCVi8UC9.js +18 -0
  36. package/dist/sign-up-BCVi8UC9.js.map +1 -0
  37. package/package.json +1 -1
  38. package/dist/handler-BBSeVt7x.js +0 -153
  39. package/dist/handler-BBSeVt7x.js.map +0 -1
  40. package/dist/handler-BKSik1j0.js +0 -83
  41. package/dist/handler-BKSik1j0.js.map +0 -1
  42. package/dist/handler-BXvh_Nx4.js +0 -95
  43. package/dist/handler-BXvh_Nx4.js.map +0 -1
  44. package/dist/handler-B_lItxOC.js +0 -66
  45. package/dist/handler-BuwKXMOu.js +0 -24
  46. package/dist/handler-BuwKXMOu.js.map +0 -1
  47. package/dist/handler-C-hPxnHG.js +0 -68
  48. package/dist/handler-C-hPxnHG.js.map +0 -1
  49. package/dist/handler-CoHpAhui.js +0 -81
  50. package/dist/handler-CoHpAhui.js.map +0 -1
  51. package/dist/handler-DfZwgoA4.js +0 -94
  52. package/dist/handler-DfZwgoA4.js.map +0 -1
  53. package/dist/handler-Eyjkxj9l.js +0 -58
  54. package/dist/handler-Eyjkxj9l.js.map +0 -1
  55. package/dist/handler-U3df_2Al.js +0 -59
  56. package/dist/handler-U3df_2Al.js.map +0 -1
  57. package/dist/index-1_ZKABa_.js +0 -20
  58. package/dist/index-1_ZKABa_.js.map +0 -1
  59. package/dist/index-D94-1Zwh.js +0 -20
  60. package/dist/index-D94-1Zwh.js.map +0 -1
  61. package/dist/middleware-8IfSkEEy.js +0 -25
  62. package/dist/middleware-8IfSkEEy.js.map +0 -1
  63. package/dist/schemas--f80aXK7.js +0 -4329
  64. package/dist/schemas--f80aXK7.js.map +0 -1
  65. package/dist/session-DoTNxRRA.js +0 -20
  66. package/dist/session-DoTNxRRA.js.map +0 -1
@@ -1,81 +0,0 @@
1
- import { models } from "@rpcbase/db";
2
- import { verifyPasswordFromStorage } from "@rpcbase/server";
3
- import { c as completeAuthSignIn } from "./session-DoTNxRRA.js";
4
- import { R as Route, r as requestSchema } from "./index-D94-1Zwh.js";
5
- const signIn = async (payload, ctx) => {
6
- const User = await models.getGlobal("RBUser", ctx);
7
- const parsed = requestSchema.safeParse(payload);
8
- if (!parsed.success) {
9
- ctx.res.status(400);
10
- return {
11
- success: false,
12
- error: "invalid_payload"
13
- };
14
- }
15
- const {
16
- email,
17
- password
18
- } = parsed.data;
19
- const user = await User.findOne({
20
- email
21
- }, {
22
- password: 1,
23
- tenants: 1,
24
- tenantRoles: 1
25
- });
26
- if (!user?.password) {
27
- ctx.res.status(401);
28
- return {
29
- success: false,
30
- error: "invalid_credentials"
31
- };
32
- }
33
- const stored = String(user.password);
34
- const passwordMatches = await verifyPasswordFromStorage(password, stored);
35
- if (!passwordMatches) {
36
- if (!stored.startsWith("$scrypt$")) {
37
- console.warn("auth::sign-in invalid stored password format", user._id.toString());
38
- }
39
- ctx.res.status(401);
40
- return {
41
- success: false,
42
- error: "invalid_credentials"
43
- };
44
- }
45
- const signedInTenants = (user.tenants || []).map(String);
46
- const defaultTenantId = signedInTenants[0];
47
- if (!defaultTenantId) {
48
- ctx.res.status(500);
49
- return {
50
- success: false,
51
- error: "tenant_unavailable"
52
- };
53
- }
54
- const tenantId = defaultTenantId;
55
- const tenantRolesMap = user.get("tenantRoles");
56
- const tenantRoles = tenantRolesMap ? Object.fromEntries(tenantRolesMap.entries()) : void 0;
57
- if (!completeAuthSignIn(ctx, {
58
- userId: user._id.toString(),
59
- currentTenantId: tenantId,
60
- signedInTenants: signedInTenants.length ? signedInTenants : [tenantId],
61
- tenantRoles
62
- })) {
63
- ctx.res.status(500);
64
- return {
65
- success: false,
66
- error: "session_unavailable"
67
- };
68
- }
69
- return {
70
- success: true,
71
- userId: user._id.toString(),
72
- tenantId
73
- };
74
- };
75
- const handler = (api) => {
76
- api.post(Route, signIn);
77
- };
78
- export {
79
- handler as default
80
- };
81
- //# sourceMappingURL=handler-CoHpAhui.js.map
@@ -1 +0,0 @@
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,94 +0,0 @@
1
- import { models } from "@rpcbase/db";
2
- import { c as completeAuthSignIn } from "./session-DoTNxRRA.js";
3
- import { o as object, b as boolean, s as string } from "./schemas--f80aXK7.js";
4
- const Route = "/api/rb/auth/verify-otp";
5
- const requestSchema = object({
6
- email: string().email(),
7
- code: string().length(6, "Code must be 6 digits"),
8
- rememberMe: boolean().default(true)
9
- });
10
- object({
11
- success: boolean(),
12
- error: string().optional(),
13
- userId: string().optional(),
14
- tenantId: string().optional()
15
- });
16
- const verifyOtp = 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
- code
29
- } = parsed.data;
30
- const user = await User.findOne({
31
- email
32
- }, {
33
- emailVerificationCode: 1,
34
- emailVerificationExpiresAt: 1,
35
- tenants: 1,
36
- tenantRoles: 1
37
- });
38
- if (!user) {
39
- ctx.res.status(404);
40
- return {
41
- success: false,
42
- error: "user_not_found"
43
- };
44
- }
45
- const storedCode = user.emailVerificationCode;
46
- const expiresAt = user.emailVerificationExpiresAt;
47
- const isExpired = expiresAt instanceof Date && expiresAt.getTime() < Date.now();
48
- if (!storedCode || storedCode !== code || isExpired) {
49
- ctx.res.status(400);
50
- return {
51
- success: false,
52
- error: "invalid_code"
53
- };
54
- }
55
- user.emailVerificationCode = void 0;
56
- user.emailVerificationExpiresAt = void 0;
57
- await user.save();
58
- const signedInTenants = (user.tenants || []).map(String);
59
- const defaultTenantId = signedInTenants[0];
60
- if (!defaultTenantId) {
61
- ctx.res.status(500);
62
- return {
63
- success: false,
64
- error: "tenant_unavailable"
65
- };
66
- }
67
- const tenantId = defaultTenantId;
68
- const tenantRolesMap = user.get("tenantRoles");
69
- const tenantRoles = tenantRolesMap ? Object.fromEntries(tenantRolesMap.entries()) : void 0;
70
- if (!completeAuthSignIn(ctx, {
71
- userId: user._id.toString(),
72
- currentTenantId: tenantId,
73
- signedInTenants: signedInTenants.length ? signedInTenants : [tenantId],
74
- tenantRoles
75
- })) {
76
- ctx.res.status(500);
77
- return {
78
- success: false,
79
- error: "session_unavailable"
80
- };
81
- }
82
- return {
83
- success: true,
84
- userId: user._id.toString(),
85
- tenantId
86
- };
87
- };
88
- const handler = (api) => {
89
- api.post(Route, verifyOtp);
90
- };
91
- export {
92
- handler as default
93
- };
94
- //# sourceMappingURL=handler-DfZwgoA4.js.map
@@ -1 +0,0 @@
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,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--f80aXK7.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-Eyjkxj9l.js.map
@@ -1 +0,0 @@
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,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--f80aXK7.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-U3df_2Al.js.map
@@ -1 +0,0 @@
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;"}
@@ -1,20 +0,0 @@
1
- import { o as object, b as boolean, s as string } from "./schemas--f80aXK7.js";
2
- const Route = "/api/rb/auth/sign-up";
3
- const requestSchema = object({
4
- email: string().nonempty("Email is required").email("Please enter a valid email address"),
5
- password: string().min(8, {
6
- message: "Password must be at least 8 characters long."
7
- }),
8
- rememberMe: boolean().default(true)
9
- });
10
- object({
11
- success: boolean(),
12
- error: string().optional(),
13
- userId: string().optional(),
14
- tenantId: string().optional()
15
- });
16
- export {
17
- Route as R,
18
- requestSchema as r
19
- };
20
- //# sourceMappingURL=index-1_ZKABa_.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-1_ZKABa_.js","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"],"names":["Route","requestSchema","z","email","string","nonempty","password","min","message","rememberMe","default","success","boolean","error","optional","userId","tenantId"],"mappings":";AAGO,MAAMA,QAAQ;AAEd,MAAMC,gBAAgBC,OACnB;AAAA,EACNC,OAAOD,OACJE,EACAC,SAAS,mBAAmB,EAC5BF,MAAM,oCAAoC;AAAA,EAC7CG,UAAUJ,OAAEE,EAASG,IAAI,GAAG;AAAA,IAAEC,SAAS;AAAA,EAAA,CAAgD;AAAA,EACvFC,YAAYP,UAAYQ,QAAQ,IAAI;AACtC,CAAC;AAI2BR,OAAS;AAAA,EACrCS,SAAST,QAAEU;AAAAA,EACXC,OAAOX,OAAEE,EAASU,SAAAA;AAAAA,EAClBC,QAAQb,OAAEE,EAASU,SAAAA;AAAAA,EACnBE,UAAUd,OAAEE,EAASU,SAAAA;AACvB,CAAC;"}
@@ -1,20 +0,0 @@
1
- import { o as object, b as boolean, s as string } from "./schemas--f80aXK7.js";
2
- const Route = "/api/rb/auth/sign-in";
3
- const requestSchema = object({
4
- email: string().nonempty("Email is required").email("Please enter a valid email address"),
5
- password: string().min(1, {
6
- message: "Password is required"
7
- }),
8
- rememberMe: boolean().default(true)
9
- });
10
- object({
11
- success: boolean(),
12
- error: string().optional(),
13
- userId: string().optional(),
14
- tenantId: string().optional()
15
- });
16
- export {
17
- Route as R,
18
- requestSchema as r
19
- };
20
- //# sourceMappingURL=index-D94-1Zwh.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-D94-1Zwh.js","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"],"names":["Route","requestSchema","z","email","string","nonempty","password","min","message","rememberMe","default","success","boolean","error","optional","userId","tenantId"],"mappings":";AAGO,MAAMA,QAAQ;AAEd,MAAMC,gBAAgBC,OAAS;AAAA,EACpCC,OAAOD,OACJE,EACAC,SAAS,mBAAmB,EAC5BF,MAAM,oCAAoC;AAAA,EAC7CG,UAAUJ,OAAEE,EAASG,IAAI,GAAG;AAAA,IAAEC,SAAS;AAAA,EAAA,CAAwB;AAAA,EAC/DC,YAAYP,UAAYQ,QAAQ,IAAI;AACtC,CAAC;AAI6BR,OAAS;AAAA,EACrCS,SAAST,QAAEU;AAAAA,EACXC,OAAOX,OAAEE,EAASU,SAAAA;AAAAA,EAClBC,QAAQb,OAAEE,EAASU,SAAAA;AAAAA,EACnBE,UAAUd,OAAEE,EAASU,SAAAA;AACvB,CAAC;"}
@@ -1,25 +0,0 @@
1
- const isAuthenticated = (req) => {
2
- const sessionUser = req.session?.user;
3
- return Boolean(sessionUser?.id);
4
- };
5
- const restrictSessionMiddleware = (req, res, next) => {
6
- if (isAuthenticated(req)) {
7
- return next();
8
- }
9
- res.status(401).json({
10
- error: "unauthorized"
11
- });
12
- };
13
- const requireSession = restrictSessionMiddleware;
14
- const redirectAuthMiddleware = (req, res, next) => {
15
- if (req.path.startsWith("/app") && !isAuthenticated(req)) {
16
- return res.redirect("/auth/sign-in");
17
- }
18
- next();
19
- };
20
- export {
21
- requireSession as a,
22
- restrictSessionMiddleware as b,
23
- redirectAuthMiddleware as r
24
- };
25
- //# sourceMappingURL=middleware-8IfSkEEy.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"middleware-8IfSkEEy.js","sources":["../src/middleware.ts"],"sourcesContent":["import type { Middleware } from \"@rpcbase/api\"\n\nimport type { AuthSessionUser } from \"./types\"\n\n\nconst isAuthenticated = (req: Parameters<Middleware>[0]): req is Parameters<Middleware<AuthSessionUser>>[0] => {\n const sessionUser = req.session?.user as { id?: unknown } | undefined\n return Boolean(sessionUser?.id)\n}\n\nexport const restrictSessionMiddleware: Middleware<AuthSessionUser> = (req, res, next) => {\n if (isAuthenticated(req)) {\n return next()\n }\n\n res.status(401).json({ error: \"unauthorized\" })\n}\n\nexport const requireSession = restrictSessionMiddleware\n\nexport const redirectAuthMiddleware: Middleware<AuthSessionUser> = (req, res, next) => {\n if (req.path.startsWith(\"/app\") && !isAuthenticated(req)) {\n return res.redirect(\"/auth/sign-in\")\n }\n\n next()\n}\n"],"names":["isAuthenticated","req","sessionUser","session","user","Boolean","id","restrictSessionMiddleware","res","next","status","json","error","requireSession","redirectAuthMiddleware","path","startsWith","redirect"],"mappings":"AAKA,MAAMA,kBAAkBA,CAACC,QAAsF;AAC7G,QAAMC,cAAcD,IAAIE,SAASC;AACjC,SAAOC,QAAQH,aAAaI,EAAE;AAChC;AAEO,MAAMC,4BAAyDA,CAACN,KAAKO,KAAKC,SAAS;AACxF,MAAIT,gBAAgBC,GAAG,GAAG;AACxB,WAAOQ,KAAAA;AAAAA,EACT;AAEAD,MAAIE,OAAO,GAAG,EAAEC,KAAK;AAAA,IAAEC,OAAO;AAAA,EAAA,CAAgB;AAChD;AAEO,MAAMC,iBAAiBN;AAEvB,MAAMO,yBAAsDA,CAACb,KAAKO,KAAKC,SAAS;AACrF,MAAIR,IAAIc,KAAKC,WAAW,MAAM,KAAK,CAAChB,gBAAgBC,GAAG,GAAG;AACxD,WAAOO,IAAIS,SAAS,eAAe;AAAA,EACrC;AAEAR,OAAAA;AACF;"}