@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.
- package/dist/api/request-password-reset/handler.d.ts +4 -1
- package/dist/api/request-password-reset/handler.d.ts.map +1 -1
- package/dist/api/request-password-reset/index.d.ts +1 -0
- package/dist/api/request-password-reset/index.d.ts.map +1 -1
- package/dist/api/resend-otp/handler.d.ts +3 -1
- package/dist/api/resend-otp/handler.d.ts.map +1 -1
- package/dist/api/sign-up/handler.d.ts +3 -1
- package/dist/api/sign-up/handler.d.ts.map +1 -1
- package/dist/components/ResendCodeButton/index.d.ts +1 -1
- package/dist/components/ResendCodeButton/index.d.ts.map +1 -1
- package/dist/{handler-DZiCZNkX.js → handler-B2Qn8_Fq.js} +62 -16
- package/dist/handler-B2Qn8_Fq.js.map +1 -0
- package/dist/{handler-DG8GMWwR.js → handler-BKSik1j0.js} +23 -4
- package/dist/handler-BKSik1j0.js.map +1 -0
- package/dist/{handler-BlhyOTyk.js → handler-BXvh_Nx4.js} +17 -4
- package/dist/handler-BXvh_Nx4.js.map +1 -0
- package/dist/{handler-BIFPHnwb.js → handler-B_lItxOC.js} +2 -2
- package/dist/{handler-BIFPHnwb.js.map → handler-B_lItxOC.js.map} +1 -1
- package/dist/{handler-4-ccxPqk.js → handler-BuwKXMOu.js} +2 -2
- package/dist/{handler-4-ccxPqk.js.map → handler-BuwKXMOu.js.map} +1 -1
- package/dist/{handler-BOCOLt9O.js → handler-C-hPxnHG.js} +2 -2
- package/dist/{handler-BOCOLt9O.js.map → handler-C-hPxnHG.js.map} +1 -1
- package/dist/{handler-Y6JMPCW0.js → handler-CoHpAhui.js} +2 -2
- package/dist/{handler-Y6JMPCW0.js.map → handler-CoHpAhui.js.map} +1 -1
- package/dist/{handler-BvztD8II.js → handler-DfZwgoA4.js} +2 -2
- package/dist/{handler-BvztD8II.js.map → handler-DfZwgoA4.js.map} +1 -1
- package/dist/{handler-Dbkf3cD8.js → handler-Eyjkxj9l.js} +2 -2
- package/dist/{handler-Dbkf3cD8.js.map → handler-Eyjkxj9l.js.map} +1 -1
- package/dist/{handler-EYTkh4N4.js → handler-U3df_2Al.js} +2 -2
- package/dist/{handler-EYTkh4N4.js.map → handler-U3df_2Al.js.map} +1 -1
- package/dist/{index-sfjvVpg9.js → index-1_ZKABa_.js} +2 -2
- package/dist/{index-sfjvVpg9.js.map → index-1_ZKABa_.js.map} +1 -1
- package/dist/{index-DznfuMJi.js → index-D94-1Zwh.js} +2 -2
- package/dist/{index-DznfuMJi.js.map → index-D94-1Zwh.js.map} +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +100 -28
- package/dist/index.js.map +1 -1
- package/dist/passwordReset.d.ts +21 -0
- package/dist/passwordReset.d.ts.map +1 -0
- package/dist/routes.js +1 -1
- package/dist/{schemas-BYptELX5.js → schemas--f80aXK7.js} +372 -1
- package/dist/{schemas-BYptELX5.js.map → schemas--f80aXK7.js.map} +1 -1
- package/package.json +12 -1
- package/dist/handler-BlhyOTyk.js.map +0 -1
- package/dist/handler-DG8GMWwR.js.map +0 -1
- package/dist/handler-DZiCZNkX.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rpcbase/auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.160.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|
|
30
30
|
"build": "wireit",
|
|
31
|
+
"test": "wireit",
|
|
31
32
|
"release": "wireit"
|
|
32
33
|
},
|
|
33
34
|
"wireit": {
|
|
@@ -60,6 +61,16 @@
|
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
63
|
},
|
|
64
|
+
"test": {
|
|
65
|
+
"command": "../../node_modules/.bin/vitest run --config ./vitest.config.ts --passWithNoTests",
|
|
66
|
+
"files": [
|
|
67
|
+
"src/**/*",
|
|
68
|
+
"tsconfig.json",
|
|
69
|
+
"vitest.config.ts",
|
|
70
|
+
"../../scripts/tsconfig.pkg.json"
|
|
71
|
+
],
|
|
72
|
+
"dependencies": []
|
|
73
|
+
},
|
|
63
74
|
"release": {
|
|
64
75
|
"command": "../../scripts/publish.js",
|
|
65
76
|
"dependencies": [
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"handler-BlhyOTyk.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 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"handler-DG8GMWwR.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 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"handler-DZiCZNkX.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;"}
|