better-auth-mercadopago 0.1.9 → 0.2.1

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.
@@ -0,0 +1,300 @@
1
+ import crypto from "node:crypto";
2
+ import { APIError } from "better-auth/api";
3
+ /**
4
+ * Verify Mercado Pago webhook signature
5
+ * https://www.mercadopago.com/developers/en/docs/subscriptions/additional-content/security/signature
6
+ */
7
+ export function verifyWebhookSignature(params) {
8
+ const { xSignature, xRequestId, dataId, secret } = params;
9
+ if (!xSignature || !xRequestId) {
10
+ return false;
11
+ }
12
+ // Parse x-signature header
13
+ // Format: "ts=1234567890,v1=hash"
14
+ const parts = xSignature.split(",");
15
+ const ts = parts.find((p) => p.startsWith("ts="))?.split("=")[1];
16
+ const hash = parts.find((p) => p.startsWith("v1="))?.split("=")[1];
17
+ if (!ts || !hash) {
18
+ return false;
19
+ }
20
+ // Build the manifest (exactly as MP does)
21
+ const manifest = `id:${dataId};request-id:${xRequestId};ts:${ts};`;
22
+ // Create HMAC SHA256
23
+ const hmac = crypto.createHmac("sha256", secret);
24
+ hmac.update(manifest);
25
+ const expectedHash = hmac.digest("hex");
26
+ // Compare hashes (constant-time comparison)
27
+ return crypto.timingSafeEqual(Buffer.from(hash), Buffer.from(expectedHash));
28
+ }
29
+ /**
30
+ * Rate limiting store (in-memory, use Redis in production)
31
+ */
32
+ class RateLimiter {
33
+ attempts = new Map();
34
+ check(key, maxAttempts, windowMs) {
35
+ const now = Date.now();
36
+ const record = this.attempts.get(key);
37
+ if (!record || now > record.resetAt) {
38
+ this.attempts.set(key, {
39
+ count: 1,
40
+ resetAt: now + windowMs,
41
+ });
42
+ return true;
43
+ }
44
+ if (record.count >= maxAttempts) {
45
+ return false;
46
+ }
47
+ record.count++;
48
+ return true;
49
+ }
50
+ cleanup() {
51
+ const now = Date.now();
52
+ for (const [key, record] of this.attempts.entries()) {
53
+ if (now > record.resetAt) {
54
+ this.attempts.delete(key);
55
+ }
56
+ }
57
+ }
58
+ }
59
+ export const rateLimiter = new RateLimiter();
60
+ // Cleanup every 5 minutes
61
+ setInterval(() => rateLimiter.cleanup(), 5 * 60 * 1000);
62
+ /**
63
+ * Validate payment amount to prevent manipulation
64
+ */
65
+ export function validatePaymentAmount(requestedAmount, mpPaymentAmount, tolerance = 0.01) {
66
+ const diff = Math.abs(requestedAmount - mpPaymentAmount);
67
+ return diff <= tolerance;
68
+ }
69
+ /**
70
+ * Sanitize metadata to prevent injection attacks
71
+ */
72
+ export function sanitizeMetadata(
73
+ // biome-ignore lint/suspicious/noExplicitAny: <necessary>
74
+ metadata) {
75
+ // biome-ignore lint/suspicious/noExplicitAny: <necessary>
76
+ const sanitized = {};
77
+ for (const [key, value] of Object.entries(metadata)) {
78
+ // Prevent prototype pollution
79
+ if (key === "__proto__" || key === "constructor" || key === "prototype") {
80
+ continue;
81
+ }
82
+ // Limit metadata size
83
+ if (typeof value === "string" && value.length > 5000) {
84
+ sanitized[key] = value.substring(0, 5000);
85
+ }
86
+ else if (typeof value === "object" && value !== null) {
87
+ // Recursively sanitize nested objects
88
+ sanitized[key] = sanitizeMetadata(value);
89
+ }
90
+ else {
91
+ sanitized[key] = value;
92
+ }
93
+ }
94
+ return sanitized;
95
+ }
96
+ /**
97
+ * Validate callback URL to prevent open redirects
98
+ */
99
+ export function validateCallbackUrl(url, allowedDomains) {
100
+ try {
101
+ const parsed = new URL(url);
102
+ // Only allow HTTPS in production
103
+ if (process.env.NODE_ENV === "production" && parsed.protocol !== "https:") {
104
+ return false;
105
+ }
106
+ // Check if domain is allowed
107
+ const hostname = parsed.hostname;
108
+ return allowedDomains.some((domain) => {
109
+ if (domain.startsWith("*.")) {
110
+ // Wildcard subdomain
111
+ const baseDomain = domain.substring(2);
112
+ return hostname.endsWith(baseDomain);
113
+ }
114
+ return hostname === domain;
115
+ });
116
+ }
117
+ catch {
118
+ return false;
119
+ }
120
+ }
121
+ /**
122
+ * Idempotency key validation
123
+ */
124
+ export function validateIdempotencyKey(key) {
125
+ // UUID v4 format or custom format
126
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
127
+ const customRegex = /^[a-zA-Z0-9_-]{8,64}$/;
128
+ return uuidRegex.test(key) || customRegex.test(key);
129
+ }
130
+ /**
131
+ * Prevent timing attacks on webhook validation
132
+ */
133
+ export function secureCompare(a, b) {
134
+ if (a.length !== b.length) {
135
+ return false;
136
+ }
137
+ try {
138
+ return crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b));
139
+ }
140
+ catch {
141
+ return false;
142
+ }
143
+ }
144
+ /**
145
+ * Error codes mapping
146
+ */
147
+ export const MercadoPagoErrorCodes = {
148
+ // Authentication
149
+ INVALID_API_KEY: "invalid_api_key",
150
+ UNAUTHORIZED: "unauthorized",
151
+ // Payment errors
152
+ INSUFFICIENT_FUNDS: "cc_rejected_insufficient_amount",
153
+ INVALID_CARD: "cc_rejected_bad_filled_card_number",
154
+ CARD_DISABLED: "cc_rejected_card_disabled",
155
+ MAX_ATTEMPTS: "cc_rejected_max_attempts",
156
+ DUPLICATED_PAYMENT: "cc_rejected_duplicated_payment",
157
+ // Subscription errors
158
+ SUBSCRIPTION_NOT_FOUND: "subscription_not_found",
159
+ SUBSCRIPTION_ALREADY_CANCELLED: "subscription_already_cancelled",
160
+ // General
161
+ INVALID_PARAMETER: "invalid_parameter",
162
+ RESOURCE_NOT_FOUND: "resource_not_found",
163
+ INTERNAL_SERVER_ERROR: "internal_server_error",
164
+ };
165
+ /**
166
+ * Custom error class for Mercado Pago errors
167
+ */
168
+ export class MercadoPagoError extends Error {
169
+ code;
170
+ message;
171
+ statusCode;
172
+ details;
173
+ constructor(code, message, statusCode = 400,
174
+ // biome-ignore lint/suspicious/noExplicitAny: <necessary>
175
+ details) {
176
+ super(message);
177
+ this.code = code;
178
+ this.message = message;
179
+ this.statusCode = statusCode;
180
+ this.details = details;
181
+ this.name = "MercadoPagoError";
182
+ }
183
+ toAPIError() {
184
+ const errorMap = {
185
+ 400: "BAD_REQUEST",
186
+ 401: "UNAUTHORIZED",
187
+ 403: "FORBIDDEN",
188
+ 404: "NOT_FOUND",
189
+ 429: "TOO_MANY_REQUESTS",
190
+ 500: "INTERNAL_SERVER_ERROR",
191
+ };
192
+ const type = errorMap[this.statusCode] || "BAD_REQUEST";
193
+ return new APIError(type, {
194
+ message: this.message,
195
+ details: this.details,
196
+ });
197
+ }
198
+ }
199
+ /**
200
+ * Handle Mercado Pago API errors
201
+ */ // biome-ignore lint/suspicious/noExplicitAny: <necessary>
202
+ export function handleMercadoPagoError(error) {
203
+ if (error.status) {
204
+ const mpError = new MercadoPagoError(error.code || "unknown_error", error.message || "An error occurred with Mercado Pago", error.status, error.cause);
205
+ throw mpError.toAPIError();
206
+ }
207
+ throw new APIError("INTERNAL_SERVER_ERROR", {
208
+ message: "Failed to process Mercado Pago request",
209
+ });
210
+ }
211
+ /**
212
+ * Webhook event types validation
213
+ */
214
+ export const VALID_WEBHOOK_TOPICS = [
215
+ "payment",
216
+ "merchant_order",
217
+ "subscription_preapproval",
218
+ "subscription_preapproval_plan",
219
+ "subscription_authorized_payment",
220
+ "point_integration_wh",
221
+ "topic_claims_integration_wh",
222
+ "topic_merchant_order_wh",
223
+ "delivery_cancellation",
224
+ ];
225
+ export function isValidWebhookTopic(topic) {
226
+ return VALID_WEBHOOK_TOPICS.includes(topic);
227
+ }
228
+ /**
229
+ * Idempotency store (in-memory, use Redis in production)
230
+ */
231
+ class IdempotencyStore {
232
+ // biome-ignore lint/suspicious/noExplicitAny: <necessary>
233
+ store = new Map();
234
+ // biome-ignore lint/suspicious/noExplicitAny: <necessary>
235
+ get(key) {
236
+ const record = this.store.get(key);
237
+ if (!record || Date.now() > record.expiresAt) {
238
+ this.store.delete(key);
239
+ return null;
240
+ }
241
+ return record.result;
242
+ }
243
+ // biome-ignore lint/suspicious/noExplicitAny: <necessary>
244
+ set(key, result, ttlMs = 24 * 60 * 60 * 1000) {
245
+ this.store.set(key, {
246
+ result,
247
+ expiresAt: Date.now() + ttlMs,
248
+ });
249
+ }
250
+ cleanup() {
251
+ const now = Date.now();
252
+ for (const [key, record] of this.store.entries()) {
253
+ if (now > record.expiresAt) {
254
+ this.store.delete(key);
255
+ }
256
+ }
257
+ }
258
+ }
259
+ export const idempotencyStore = new IdempotencyStore();
260
+ // Cleanup every hour
261
+ setInterval(() => idempotencyStore.cleanup(), 60 * 60 * 1000);
262
+ /**
263
+ * CSRF token validation
264
+ */
265
+ export function validateCSRFToken(token, expectedToken) {
266
+ return secureCompare(token, expectedToken);
267
+ }
268
+ /**
269
+ * Input validation helpers
270
+ */
271
+ export const ValidationRules = {
272
+ email: (email) => {
273
+ const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
274
+ return regex.test(email) && email.length <= 255;
275
+ },
276
+ amount: (amount) => {
277
+ return amount > 0 && amount <= 999999999 && !Number.isNaN(amount);
278
+ },
279
+ currency: (currency) => {
280
+ const validCurrencies = [
281
+ "ARS",
282
+ "BRL",
283
+ "CLP",
284
+ "MXN",
285
+ "COP",
286
+ "PEN",
287
+ "UYU",
288
+ "USD",
289
+ ];
290
+ return validCurrencies.includes(currency);
291
+ },
292
+ frequency: (frequency) => {
293
+ return frequency > 0 && frequency <= 365 && Number.isInteger(frequency);
294
+ },
295
+ userId: (userId) => {
296
+ // UUID or custom ID format
297
+ return /^[a-zA-Z0-9_-]{1,100}$/.test(userId);
298
+ },
299
+ };
300
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAKtC;IACA,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAE1D,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,EAAE,CAAC;QAChC,OAAO,KAAK,CAAC;IACd,CAAC;IAED,2BAA2B;IAC3B,kCAAkC;IAClC,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACjE,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAEnE,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,OAAO,KAAK,CAAC;IACd,CAAC;IAED,0CAA0C;IAC1C,MAAM,QAAQ,GAAG,MAAM,MAAM,eAAe,UAAU,OAAO,EAAE,GAAG,CAAC;IAEnE,qBAAqB;IACrB,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACjD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACtB,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAExC,4CAA4C;IAC5C,OAAO,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED;;GAEG;AACH,MAAM,WAAW;IACR,QAAQ,GAAoD,IAAI,GAAG,EAAE,CAAC;IAE9E,KAAK,CAAC,GAAW,EAAE,WAAmB,EAAE,QAAgB;QACvD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEtC,IAAI,CAAC,MAAM,IAAI,GAAG,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YACrC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE;gBACtB,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,GAAG,GAAG,QAAQ;aACvB,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACb,CAAC;QAED,IAAI,MAAM,CAAC,KAAK,IAAI,WAAW,EAAE,CAAC;YACjC,OAAO,KAAK,CAAC;QACd,CAAC;QAED,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,OAAO,IAAI,CAAC;IACb,CAAC;IAED,OAAO;QACN,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;YACrD,IAAI,GAAG,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;gBAC1B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC3B,CAAC;QACF,CAAC;IACF,CAAC;CACD;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;AAE7C,0BAA0B;AAC1B,WAAW,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;AAExD;;GAEG;AACH,MAAM,UAAU,qBAAqB,CACpC,eAAuB,EACvB,eAAuB,EACvB,YAAoB,IAAI;IAExB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,GAAG,eAAe,CAAC,CAAC;IACzD,OAAO,IAAI,IAAI,SAAS,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;AAC/B,0DAA0D;AAC1D,QAA6B;IAG7B,0DAA0D;IAC1D,MAAM,SAAS,GAAwB,EAAE,CAAC;IAE1C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrD,8BAA8B;QAC9B,IAAI,GAAG,KAAK,WAAW,IAAI,GAAG,KAAK,aAAa,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;YACzE,SAAS;QACV,CAAC;QAED,sBAAsB;QACtB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;YACtD,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QAC3C,CAAC;aAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACxD,sCAAsC;YACtC,SAAS,CAAC,GAAG,CAAC,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACP,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACxB,CAAC;IACF,CAAC;IAED,OAAO,SAAS,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAClC,GAAW,EACX,cAAwB;IAExB,IAAI,CAAC;QACJ,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAE5B,iCAAiC;QACjC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC3E,OAAO,KAAK,CAAC;QACd,CAAC;QAED,6BAA6B;QAC7B,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QACjC,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACrC,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC7B,qBAAqB;gBACrB,MAAM,UAAU,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;gBACvC,OAAO,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;YACtC,CAAC;YACD,OAAO,QAAQ,KAAK,MAAM,CAAC;QAC5B,CAAC,CAAC,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAC;IACd,CAAC;AACF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,GAAW;IACjD,kCAAkC;IAClC,MAAM,SAAS,GACd,wEAAwE,CAAC;IAC1E,MAAM,WAAW,GAAG,uBAAuB,CAAC;IAE5C,OAAO,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACrD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,CAAS,EAAE,CAAS;IACjD,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACJ,OAAO,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAC;IACd,CAAC;AACF,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACpC,iBAAiB;IACjB,eAAe,EAAE,iBAAiB;IAClC,YAAY,EAAE,cAAc;IAE5B,iBAAiB;IACjB,kBAAkB,EAAE,iCAAiC;IACrD,YAAY,EAAE,oCAAoC;IAClD,aAAa,EAAE,2BAA2B;IAC1C,YAAY,EAAE,0BAA0B;IACxC,kBAAkB,EAAE,gCAAgC;IAEpD,sBAAsB;IACtB,sBAAsB,EAAE,wBAAwB;IAChD,8BAA8B,EAAE,gCAAgC;IAEhE,UAAU;IACV,iBAAiB,EAAE,mBAAmB;IACtC,kBAAkB,EAAE,oBAAoB;IACxC,qBAAqB,EAAE,uBAAuB;CACrC,CAAC;AAEX;;GAEG;AACH,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAElC;IACS;IACT;IAEA;IALR,YACQ,IAAY,EACH,OAAe,EACxB,aAAqB,GAAG;IAC/B,0DAA0D;IACnD,OAAa;QAEpB,KAAK,CAAC,OAAO,CAAC,CAAC;QANR,SAAI,GAAJ,IAAI,CAAQ;QACH,YAAO,GAAP,OAAO,CAAQ;QACxB,eAAU,GAAV,UAAU,CAAc;QAExB,YAAO,GAAP,OAAO,CAAM;QAGpB,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IAChC,CAAC;IAED,UAAU;QACT,MAAM,QAAQ,GAsDV;YACH,GAAG,EAAE,aAAa;YAClB,GAAG,EAAE,cAAc;YACnB,GAAG,EAAE,WAAW;YAChB,GAAG,EAAE,WAAW;YAChB,GAAG,EAAE,mBAAmB;YACxB,GAAG,EAAE,uBAAuB;SAC5B,CAAC;QAEF,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,aAAa,CAAC;QAExD,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE;YACzB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,OAAO,EAAE,IAAI,CAAC,OAAO;SACrB,CAAC,CAAC;IACJ,CAAC;CACD;AAED;;GAEG,CAAC,0DAA0D;AAC9D,MAAM,UAAU,sBAAsB,CAAC,KAAU;IAChD,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QAClB,MAAM,OAAO,GAAG,IAAI,gBAAgB,CACnC,KAAK,CAAC,IAAI,IAAI,eAAe,EAC7B,KAAK,CAAC,OAAO,IAAI,qCAAqC,EACtD,KAAK,CAAC,MAAM,EACZ,KAAK,CAAC,KAAK,CACX,CAAC;QACF,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;IAC5B,CAAC;IAED,MAAM,IAAI,QAAQ,CAAC,uBAAuB,EAAE;QAC3C,OAAO,EAAE,wCAAwC;KACjD,CAAC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IACnC,SAAS;IACT,gBAAgB;IAChB,0BAA0B;IAC1B,+BAA+B;IAC/B,iCAAiC;IACjC,sBAAsB;IACtB,6BAA6B;IAC7B,yBAAyB;IACzB,uBAAuB;CACd,CAAC;AAIX,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAChD,OAAO,oBAAoB,CAAC,QAAQ,CAAC,KAAqB,CAAC,CAAC;AAC7D,CAAC;AAED;;GAEG;AACH,MAAM,gBAAgB;IACrB,0DAA0D;IAClD,KAAK,GAAoD,IAAI,GAAG,EAAE,CAAC;IAE3E,0DAA0D;IAC1D,GAAG,CAAC,GAAW;QACd,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;YAC9C,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,IAAI,CAAC;QACb,CAAC;QACD,OAAO,MAAM,CAAC,MAAM,CAAC;IACtB,CAAC;IAED,0DAA0D;IAC1D,GAAG,CAAC,GAAW,EAAE,MAAW,EAAE,QAAgB,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;QAChE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YACnB,MAAM;YACN,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;SAC7B,CAAC,CAAC;IACJ,CAAC;IAED,OAAO;QACN,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YAClD,IAAI,GAAG,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;gBAC5B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACxB,CAAC;QACF,CAAC;IACF,CAAC;CACD;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,gBAAgB,EAAE,CAAC;AAEvD,qBAAqB;AACrB,WAAW,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;AAE9D;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAChC,KAAa,EACb,aAAqB;IAErB,OAAO,aAAa,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC9B,KAAK,EAAE,CAAC,KAAa,EAAW,EAAE;QACjC,MAAM,KAAK,GAAG,4BAA4B,CAAC;QAC3C,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG,CAAC;IACjD,CAAC;IAED,MAAM,EAAE,CAAC,MAAc,EAAW,EAAE;QACnC,OAAO,MAAM,GAAG,CAAC,IAAI,MAAM,IAAI,SAAS,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACnE,CAAC;IAED,QAAQ,EAAE,CAAC,QAAgB,EAAW,EAAE;QACvC,MAAM,eAAe,GAAG;YACvB,KAAK;YACL,KAAK;YACL,KAAK;YACL,KAAK;YACL,KAAK;YACL,KAAK;YACL,KAAK;YACL,KAAK;SACL,CAAC;QACF,OAAO,eAAe,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;IAED,SAAS,EAAE,CAAC,SAAiB,EAAW,EAAE;QACzC,OAAO,SAAS,GAAG,CAAC,IAAI,SAAS,IAAI,GAAG,IAAI,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACzE,CAAC;IAED,MAAM,EAAE,CAAC,MAAc,EAAW,EAAE;QACnC,2BAA2B;QAC3B,OAAO,wBAAwB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9C,CAAC;CACD,CAAC"}