@convex-dev/better-auth 0.12.0 → 0.12.2

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 (57) hide show
  1. package/dist/client/adapter-utils.d.ts.map +1 -1
  2. package/dist/client/adapter-utils.js +4 -2
  3. package/dist/client/adapter-utils.js.map +1 -1
  4. package/dist/client/adapter.d.ts +0 -1
  5. package/dist/client/adapter.d.ts.map +1 -1
  6. package/dist/client/adapter.js.map +1 -1
  7. package/dist/client/create-api.d.ts.map +1 -1
  8. package/dist/client/create-api.js +17 -7
  9. package/dist/client/create-api.js.map +1 -1
  10. package/dist/client/create-client.d.ts +0 -2
  11. package/dist/client/create-client.d.ts.map +1 -1
  12. package/dist/client/create-client.js.map +1 -1
  13. package/dist/component/_generated/api.d.ts +2 -2
  14. package/dist/component/_generated/api.d.ts.map +1 -1
  15. package/dist/component/_generated/component.d.ts +0 -3
  16. package/dist/component/_generated/component.d.ts.map +1 -1
  17. package/dist/component/testTriggerHandlers.d.ts +10 -0
  18. package/dist/component/testTriggerHandlers.d.ts.map +1 -0
  19. package/dist/component/testTriggerHandlers.js +25 -0
  20. package/dist/component/testTriggerHandlers.js.map +1 -0
  21. package/dist/nextjs/index.d.ts.map +1 -1
  22. package/dist/nextjs/index.js +24 -9
  23. package/dist/nextjs/index.js.map +1 -1
  24. package/dist/plugins/cross-domain/client.d.ts.map +1 -1
  25. package/dist/plugins/cross-domain/client.js +21 -1
  26. package/dist/plugins/cross-domain/client.js.map +1 -1
  27. package/dist/react-start/index.d.ts.map +1 -1
  28. package/dist/react-start/index.js +5 -0
  29. package/dist/react-start/index.js.map +1 -1
  30. package/dist/utils/index.d.ts.map +1 -1
  31. package/dist/utils/index.js +1 -0
  32. package/dist/utils/index.js.map +1 -1
  33. package/dist/version.d.ts +1 -1
  34. package/dist/version.js +1 -1
  35. package/package.json +24 -24
  36. package/src/client/adapter-utils.ts +4 -2
  37. package/src/client/adapter.test.ts +215 -6
  38. package/src/client/adapter.ts +0 -1
  39. package/src/client/create-api.ts +36 -10
  40. package/src/client/create-client.ts +0 -2
  41. package/src/client/triggers.test.ts +58 -0
  42. package/src/component/_generated/api.ts +2 -2
  43. package/src/component/_generated/component.ts +0 -3
  44. package/src/component/testTriggerHandlers.ts +27 -0
  45. package/src/nextjs/index.test.ts +109 -0
  46. package/src/nextjs/index.ts +28 -9
  47. package/src/plugins/cross-domain/client.test.ts +26 -7
  48. package/src/plugins/cross-domain/client.ts +28 -2
  49. package/src/react-start/index.test.ts +91 -0
  50. package/src/react-start/index.ts +5 -0
  51. package/src/utils/index.ts +1 -0
  52. package/src/version.ts +1 -1
  53. package/dist/component/adapterTest.d.ts +0 -3
  54. package/dist/component/adapterTest.d.ts.map +0 -1
  55. package/dist/component/adapterTest.js +0 -202
  56. package/dist/component/adapterTest.js.map +0 -1
  57. package/src/component/adapterTest.ts +0 -275
@@ -191,13 +191,10 @@ describe("crossDomainClient", () => {
191
191
  });
192
192
 
193
193
  describe("onSuccess handler", () => {
194
- it("clears cookies when get-session returns null", async () => {
195
- storage.set(
196
- cookieName,
197
- JSON.stringify({
198
- "better-auth.session_token": { value: "stale", expires: null },
199
- })
200
- );
194
+ it("clears session cookies when get-session returns null", async () => {
195
+ storage.set(cookieName, JSON.stringify({
196
+ "better-auth.session_token": { value: "stale", expires: null },
197
+ }));
201
198
 
202
199
  const onSuccess = getOnSuccessHook();
203
200
  await onSuccess({
@@ -209,6 +206,28 @@ describe("crossDomainClient", () => {
209
206
  expect(storage.get(cookieName)).toBe("{}");
210
207
  });
211
208
 
209
+ it("preserves two_factor cookie when get-session returns null", async () => {
210
+ storage.set(cookieName, JSON.stringify({
211
+ "better-auth.session_token": { value: "stale", expires: null },
212
+ "better-auth.session_data": { value: "data", expires: null },
213
+ "better-auth.convex_jwt": { value: "jwt", expires: null },
214
+ "better-auth.two_factor": { value: "2fa-challenge-token", expires: null },
215
+ }));
216
+
217
+ const onSuccess = getOnSuccessHook();
218
+ await onSuccess({
219
+ data: null,
220
+ request: { url: new URL("https://example.com/api/auth/get-session") },
221
+ response: { headers: new Headers() },
222
+ } as any);
223
+
224
+ const result = JSON.parse(storage.get(cookieName)!);
225
+ expect(result["better-auth.two_factor"]).toEqual({ value: "2fa-challenge-token", expires: null });
226
+ expect(result["better-auth.session_token"]).toBeUndefined();
227
+ expect(result["better-auth.session_data"]).toBeUndefined();
228
+ expect(result["better-auth.convex_jwt"]).toBeUndefined();
229
+ });
230
+
212
231
  it("preserves cookies when get-session returns data", async () => {
213
232
  const existingCookies = JSON.stringify({
214
233
  "better-auth.session_token": { value: "valid", expires: null },
@@ -47,7 +47,9 @@ export function getCookie(cookie: string) {
47
47
  // noop
48
48
  }
49
49
  return Object.entries(parsed)
50
- .filter(([, value]) => !value.expires || new Date(value.expires) >= new Date())
50
+ .filter(
51
+ ([, value]) => !value.expires || new Date(value.expires) >= new Date()
52
+ )
51
53
  .map(([key, value]) => `${key}=${value.value}`)
52
54
  .join("; ");
53
55
  }
@@ -185,7 +187,31 @@ export const crossDomainClient = (
185
187
  const data = context.data;
186
188
  storage.setItem(localCacheName, JSON.stringify(data));
187
189
  if (data === null) {
188
- storage.setItem(cookieName, "{}");
190
+ // Preserve non-session cookies (e.g. two_factor) when
191
+ // get-session returns null during 2FA pending state.
192
+ // Previously this unconditionally set cookieName to "{}",
193
+ // which wiped the two_factor challenge token needed for
194
+ // verifyTotp in cross-domain setups.
195
+ const prev = storage.getItem(cookieName);
196
+ try {
197
+ const parsed = JSON.parse(prev || "{}") as Record<
198
+ string,
199
+ unknown
200
+ >;
201
+ const preserved: Record<string, unknown> = {};
202
+ for (const [key, val] of Object.entries(parsed)) {
203
+ if (
204
+ !key.includes("session_token") &&
205
+ !key.includes("session_data") &&
206
+ !key.includes("convex_jwt")
207
+ ) {
208
+ preserved[key] = val;
209
+ }
210
+ }
211
+ storage.setItem(cookieName, JSON.stringify(preserved));
212
+ } catch {
213
+ storage.setItem(cookieName, "{}");
214
+ }
189
215
  }
190
216
  }
191
217
  },
@@ -0,0 +1,91 @@
1
+ import { afterEach, describe, expect, it, vi } from "vitest";
2
+ import { convexBetterAuthReactStart } from "./index.js";
3
+
4
+ const SITE_URL = "https://test.convex.site";
5
+ const CONVEX_URL = "https://test.convex.cloud";
6
+
7
+ const setup = () => {
8
+ const { handler } = convexBetterAuthReactStart({
9
+ convexUrl: CONVEX_URL,
10
+ convexSiteUrl: SITE_URL,
11
+ });
12
+ const fetchSpy = vi
13
+ .spyOn(globalThis, "fetch")
14
+ .mockResolvedValue(new Response());
15
+ return { handler, fetchSpy };
16
+ };
17
+
18
+ const initOf = (
19
+ spy: ReturnType<typeof vi.spyOn>
20
+ ): RequestInit & { duplex?: string } =>
21
+ (spy.mock.calls[0]?.[1] as RequestInit & { duplex?: string }) ?? {};
22
+
23
+ const headersOf = (spy: ReturnType<typeof vi.spyOn>): Headers =>
24
+ new Headers(initOf(spy).headers);
25
+
26
+ describe("convexBetterAuthReactStart handler", () => {
27
+ afterEach(() => {
28
+ vi.restoreAllMocks();
29
+ });
30
+
31
+ it("strips hop-by-hop headers from the forwarded request", async () => {
32
+ const { handler, fetchSpy } = setup();
33
+ const request = new Request(
34
+ "https://app.example.com/api/auth/sign-in/email",
35
+ {
36
+ method: "POST",
37
+ headers: {
38
+ "transfer-encoding": "chunked",
39
+ "content-length": "42",
40
+ connection: "keep-alive",
41
+ "content-type": "application/json",
42
+ },
43
+ body: JSON.stringify({ email: "test@example.com" }),
44
+ }
45
+ );
46
+ await handler(request);
47
+ const headers = headersOf(fetchSpy);
48
+ expect(headers.get("transfer-encoding")).toBeNull();
49
+ expect(headers.get("content-length")).toBeNull();
50
+ expect(headers.get("connection")).toBeNull();
51
+ });
52
+
53
+ it("forwards to upstream URL preserving path and query", async () => {
54
+ const { handler, fetchSpy } = setup();
55
+ const request = new Request(
56
+ "https://app.example.com/api/auth/sign-in/email?foo=bar",
57
+ { method: "POST", body: "{}" }
58
+ );
59
+ await handler(request);
60
+ expect(fetchSpy.mock.calls[0]?.[0]).toBe(
61
+ `${SITE_URL}/api/auth/sign-in/email?foo=bar`
62
+ );
63
+ });
64
+
65
+ it("sets host and forwarding headers", async () => {
66
+ const { handler, fetchSpy } = setup();
67
+ const request = new Request(
68
+ "https://app.example.com/api/auth/sign-in/email",
69
+ { method: "POST", body: "{}" }
70
+ );
71
+ await handler(request);
72
+ const headers = headersOf(fetchSpy);
73
+ expect(headers.get("host")).toBe(new URL(SITE_URL).host);
74
+ expect(headers.get("x-forwarded-host")).toBe("app.example.com");
75
+ expect(headers.get("x-forwarded-proto")).toBe("https");
76
+ expect(headers.get("x-better-auth-forwarded-host")).toBe("app.example.com");
77
+ expect(headers.get("x-better-auth-forwarded-proto")).toBe("https");
78
+ });
79
+
80
+ it("streams the request body with duplex: half", async () => {
81
+ const { handler, fetchSpy } = setup();
82
+ const request = new Request(
83
+ "https://app.example.com/api/auth/sign-in/email",
84
+ { method: "POST", body: JSON.stringify({ email: "test@example.com" }) }
85
+ );
86
+ await handler(request);
87
+ const init = initOf(fetchSpy);
88
+ expect(init.duplex).toBe("half");
89
+ expect(init.body).toBeDefined();
90
+ });
91
+ });
@@ -63,6 +63,11 @@ const handler = (request: Request, opts: { convexSiteUrl: string }) => {
63
63
  const requestUrl = new URL(request.url);
64
64
  const nextUrl = `${opts.convexSiteUrl}${requestUrl.pathname}${requestUrl.search}`;
65
65
  const headers = new Headers(request.headers);
66
+ // Strip hop-by-hop headers inherited from the incoming request; undici
67
+ // rejects an outbound `transfer-encoding: chunked` header value.
68
+ headers.delete("transfer-encoding");
69
+ headers.delete("content-length");
70
+ headers.delete("connection");
66
71
  headers.set("accept-encoding", "application/json");
67
72
  headers.set("host", new URL(opts.convexSiteUrl).host);
68
73
  headers.set("x-forwarded-host", requestUrl.host);
@@ -137,6 +137,7 @@ export const getToken = async (
137
137
  headers: Headers,
138
138
  opts?: GetTokenOptions
139
139
  ) => {
140
+ headers.set("host", new URL(siteUrl).host)
140
141
  const fetchToken = async () => {
141
142
  const basePath = opts?.basePath
142
143
  ? (opts.basePath.startsWith("/") ? opts.basePath : `/${opts.basePath}`)
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const VERSION = "0.12.0";
1
+ export const VERSION = "0.12.2";
@@ -1,3 +0,0 @@
1
- import type { EmptyObject } from "convex-helpers";
2
- export declare const runTests: import("convex/server").RegisteredAction<"public", EmptyObject, Promise<void>>;
3
- //# sourceMappingURL=adapterTest.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"adapterTest.d.ts","sourceRoot":"","sources":["../../src/component/adapterTest.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAyGlD,eAAO,MAAM,QAAQ,gFAoKpB,CAAC"}
@@ -1,202 +0,0 @@
1
- import { createClient } from "../client/index.js";
2
- import { internal } from "./_generated/api.js";
3
- import { action } from "./_generated/server.js";
4
- // Tests need to run inside of a Convex function to use the Convex adapter.
5
- // Test dependencies are dynamically imported to keep them out of the
6
- // production bundle. convex-test runs in the vitest process, so vitest
7
- // globals are available through dynamic imports.
8
- const NORMAL_DISABLED_TESTS = [
9
- // dynamic-schema-plugin-table/dynamic-schema-additional-fields:
10
- // Convex validators are static in this harness, so runtime schema mutation
11
- // tests are validated in dedicated profiles instead.
12
- "create - should apply default values to fields",
13
- "create - should return null for nullable foreign keys",
14
- "create - should support arrays",
15
- "create - should support json",
16
- // convex-id-generation:
17
- // Convex controls generated IDs at write time.
18
- "create - should use generateId if provided",
19
- // offset-unsupported:
20
- // Convex adapter rejects offset pagination.
21
- "findMany - should be able to perform a complex limited join",
22
- "findMany - should find many models with limit and offset",
23
- "findMany - should find many models with offset",
24
- "findMany - should find many models with sortBy and limit and offset",
25
- "findMany - should find many models with sortBy and limit and offset and where",
26
- "findMany - should find many models with sortBy and offset",
27
- "findMany - should find many with both one-to-one and one-to-many joins",
28
- "findMany - should find many with join and offset",
29
- "findMany - should find many with join, where, limit, and offset",
30
- "findMany - should find many with one-to-one join",
31
- "findMany - should handle mixed joins correctly when some are missing",
32
- "findMany - should return empty array when base records don't exist with joins",
33
- "findMany - should return null for one-to-one join when joined records don't exist",
34
- "findMany - should select fields with one-to-one join",
35
- // profile-specific coverage:
36
- // These are intentionally exercised in dedicated profile suites.
37
- "findOne - backwards join with modified field name (session base, users-table join)",
38
- "findOne - multiple joins should return result even when some joined tables have no matching rows",
39
- "findOne - should find a model with modified field name",
40
- "findOne - should find a model with modified model name",
41
- "findOne - should join a model with modified field name",
42
- "findOne - should not apply defaultValue if value not found",
43
- "findOne - should return an object for one-to-one joins",
44
- "findOne - should return null for failed base model lookup that has joins",
45
- "findOne - should return null for one-to-one join when joined record doesn't exist",
46
- "findOne - should select fields with one-to-one join",
47
- "findOne - should work with both one-to-one and one-to-many joins",
48
- ];
49
- const toDisableMap = (testNames) => Object.fromEntries(testNames.map((testName) => [testName, true]));
50
- const toEnableOnlyMap = (testNames) => ({
51
- ALL: true,
52
- ...Object.fromEntries(testNames.map((testName) => [testName, false])),
53
- });
54
- const UUID_SUITE_TESTS = ["init - tests"];
55
- const getOverrideBetterAuthOptions = (opts) => ({
56
- ...opts,
57
- advanced: {
58
- ...opts.advanced,
59
- database: {
60
- ...opts.advanced?.database,
61
- generateId: "uuid",
62
- },
63
- },
64
- });
65
- const internalWithTestProfiles = internal;
66
- const baseProfileApi = {
67
- adapter: internalWithTestProfiles.adapter,
68
- adapterTest: internalWithTestProfiles.adapterTest,
69
- };
70
- const profileApi = (name) => {
71
- return { adapter: internalWithTestProfiles.testProfiles[name] };
72
- };
73
- const additionalFieldsProfileApi = profileApi("adapterAdditionalFields");
74
- const pluginTableProfileApi = profileApi("adapterPluginTable");
75
- const renameFieldProfileApi = profileApi("adapterRenameField");
76
- const renameUserCustomProfileApi = profileApi("adapterRenameUserCustom");
77
- const renameUserTableProfileApi = profileApi("adapterRenameUserTable");
78
- const organizationJoinsProfileApi = profileApi("adapterOrganizationJoins");
79
- export const runTests = action(async (ctx, _args) => {
80
- const testUtilsImport = "@better-auth/test-utils/adapter";
81
- const { testAdapter, transactionsTestSuite, uuidTestSuite } = await import(testUtilsImport);
82
- const adapterFactoryImport = "../test/adapter-factory/index.js";
83
- const { coreNormalTestSuite, coreAuthFlowTestSuite, additionalFieldsNormalTestSuite, additionalFieldsAuthFlowTestSuite, pluginTableNormalTestSuite, renameFieldAndJoinTestSuite, renameModelUserCustomTestSuite, renameModelUserTableTestSuite, multiJoinsMissingRowsTestSuite, convexCustomTestSuite, } = await import(adapterFactoryImport);
84
- const baseProfileClient = createClient(baseProfileApi, {
85
- verbose: false,
86
- });
87
- const additionalFieldsProfileClient = createClient(additionalFieldsProfileApi, {
88
- verbose: false,
89
- });
90
- const pluginTableProfileClient = createClient(pluginTableProfileApi, {
91
- verbose: false,
92
- });
93
- const renameFieldProfileClient = createClient(renameFieldProfileApi, {
94
- verbose: false,
95
- });
96
- const renameUserCustomProfileClient = createClient(renameUserCustomProfileApi, {
97
- verbose: false,
98
- });
99
- const renameUserTableProfileClient = createClient(renameUserTableProfileApi, {
100
- verbose: false,
101
- });
102
- const organizationJoinsProfileClient = createClient(organizationJoinsProfileApi, {
103
- verbose: false,
104
- });
105
- const { execute: executeBaseProfile } = await testAdapter({
106
- adapter: () => {
107
- return baseProfileClient.adapter(ctx);
108
- },
109
- runMigrations: () => {
110
- // Convex schema is static — no migrations needed.
111
- },
112
- overrideBetterAuthOptions: getOverrideBetterAuthOptions,
113
- tests: [
114
- coreNormalTestSuite({
115
- disableTests: toDisableMap(NORMAL_DISABLED_TESTS),
116
- }),
117
- uuidTestSuite({
118
- disableTests: toEnableOnlyMap(UUID_SUITE_TESTS),
119
- }),
120
- transactionsTestSuite({ disableTests: { ALL: true } }),
121
- coreAuthFlowTestSuite(),
122
- convexCustomTestSuite(),
123
- ],
124
- });
125
- const { execute: executeAdditionalFieldsProfile } = await testAdapter({
126
- adapter: () => {
127
- return additionalFieldsProfileClient.adapter(ctx);
128
- },
129
- runMigrations: () => {
130
- // Convex schema is static — no migrations needed.
131
- },
132
- overrideBetterAuthOptions: getOverrideBetterAuthOptions,
133
- prefixTests: "profile:additional-fields",
134
- tests: [
135
- additionalFieldsNormalTestSuite(),
136
- additionalFieldsAuthFlowTestSuite(),
137
- ],
138
- });
139
- const { execute: executePluginTableProfile } = await testAdapter({
140
- adapter: () => {
141
- return pluginTableProfileClient.adapter(ctx);
142
- },
143
- runMigrations: () => {
144
- // Convex schema is static — no migrations needed.
145
- },
146
- overrideBetterAuthOptions: getOverrideBetterAuthOptions,
147
- prefixTests: "profile:plugin-table",
148
- tests: [pluginTableNormalTestSuite()],
149
- });
150
- const { execute: executeRenameFieldProfile } = await testAdapter({
151
- adapter: () => {
152
- return renameFieldProfileClient.adapter(ctx);
153
- },
154
- runMigrations: () => {
155
- // Convex schema is static — no migrations needed.
156
- },
157
- overrideBetterAuthOptions: getOverrideBetterAuthOptions,
158
- prefixTests: "profile:rename-field-join",
159
- tests: [renameFieldAndJoinTestSuite()],
160
- });
161
- const { execute: executeRenameUserCustomProfile } = await testAdapter({
162
- adapter: () => {
163
- return renameUserCustomProfileClient.adapter(ctx);
164
- },
165
- runMigrations: () => {
166
- // Convex schema is static — no migrations needed.
167
- },
168
- overrideBetterAuthOptions: getOverrideBetterAuthOptions,
169
- prefixTests: "profile:rename-user-custom",
170
- tests: [renameModelUserCustomTestSuite()],
171
- });
172
- const { execute: executeRenameUserTableProfile } = await testAdapter({
173
- adapter: () => {
174
- return renameUserTableProfileClient.adapter(ctx);
175
- },
176
- runMigrations: () => {
177
- // Convex schema is static — no migrations needed.
178
- },
179
- overrideBetterAuthOptions: getOverrideBetterAuthOptions,
180
- prefixTests: "profile:rename-user-table",
181
- tests: [renameModelUserTableTestSuite()],
182
- });
183
- const { execute: executeOrganizationJoinsProfile } = await testAdapter({
184
- adapter: () => {
185
- return organizationJoinsProfileClient.adapter(ctx);
186
- },
187
- runMigrations: () => {
188
- // Convex schema is static — no migrations needed.
189
- },
190
- overrideBetterAuthOptions: getOverrideBetterAuthOptions,
191
- prefixTests: "profile:organization-joins",
192
- tests: [multiJoinsMissingRowsTestSuite()],
193
- });
194
- await executeBaseProfile();
195
- await executeAdditionalFieldsProfile();
196
- await executePluginTableProfile();
197
- await executeRenameFieldProfile();
198
- await executeRenameUserCustomProfile();
199
- await executeRenameUserTableProfile();
200
- await executeOrganizationJoinsProfile();
201
- });
202
- //# sourceMappingURL=adapterTest.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"adapterTest.js","sourceRoot":"","sources":["../../src/component/adapterTest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAOhD,2EAA2E;AAC3E,qEAAqE;AACrE,uEAAuE;AACvE,iDAAiD;AAEjD,MAAM,qBAAqB,GAAG;IAC5B,gEAAgE;IAChE,2EAA2E;IAC3E,qDAAqD;IACrD,gDAAgD;IAChD,uDAAuD;IACvD,gCAAgC;IAChC,8BAA8B;IAC9B,wBAAwB;IACxB,+CAA+C;IAC/C,4CAA4C;IAC5C,sBAAsB;IACtB,4CAA4C;IAC5C,6DAA6D;IAC7D,0DAA0D;IAC1D,gDAAgD;IAChD,qEAAqE;IACrE,+EAA+E;IAC/E,2DAA2D;IAC3D,wEAAwE;IACxE,kDAAkD;IAClD,iEAAiE;IACjE,kDAAkD;IAClD,sEAAsE;IACtE,+EAA+E;IAC/E,mFAAmF;IACnF,sDAAsD;IACtD,6BAA6B;IAC7B,iEAAiE;IACjE,oFAAoF;IACpF,kGAAkG;IAClG,wDAAwD;IACxD,wDAAwD;IACxD,wDAAwD;IACxD,4DAA4D;IAC5D,wDAAwD;IACxD,0EAA0E;IAC1E,mFAAmF;IACnF,qDAAqD;IACrD,kEAAkE;CAC1D,CAAC;AAEX,MAAM,YAAY,GAAG,CAAC,SAA4B,EAAE,EAAE,CACpD,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AAEpE,MAAM,eAAe,GAAG,CAAC,SAA4B,EAAE,EAAE,CAAC,CAAC;IACzD,GAAG,EAAE,IAAI;IACT,GAAG,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;CACtE,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,CAAC,cAAc,CAAU,CAAC;AAEnD,MAAM,4BAA4B,GAAG,CAAC,IAAuB,EAAE,EAAE,CAAC,CAAC;IACjE,GAAG,IAAI;IACP,QAAQ,EAAE;QACR,GAAG,IAAI,CAAC,QAAQ;QAChB,QAAQ,EAAE;YACR,GAAG,IAAI,CAAC,QAAQ,EAAE,QAAQ;YAC1B,UAAU,EAAE,MAAM;SACnB;KACF;CACF,CAAC,CAAC;AAiBH,MAAM,wBAAwB,GAAG,QAA+C,CAAC;AAEjF,MAAM,cAAc,GAAG;IACrB,OAAO,EAAE,wBAAwB,CAAC,OAAO;IACzC,WAAW,EAAE,wBAAwB,CAAC,WAAW;CAClD,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,IAAqB,EAA8B,EAAE;IACvE,OAAO,EAAE,OAAO,EAAE,wBAAwB,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;AAClE,CAAC,CAAC;AAEF,MAAM,0BAA0B,GAAG,UAAU,CAAC,yBAAyB,CAAC,CAAC;AACzE,MAAM,qBAAqB,GAAG,UAAU,CAAC,oBAAoB,CAAC,CAAC;AAC/D,MAAM,qBAAqB,GAAG,UAAU,CAAC,oBAAoB,CAAC,CAAC;AAC/D,MAAM,0BAA0B,GAAG,UAAU,CAAC,yBAAyB,CAAC,CAAC;AACzE,MAAM,yBAAyB,GAAG,UAAU,CAAC,wBAAwB,CAAC,CAAC;AACvE,MAAM,2BAA2B,GAAG,UAAU,CAAC,0BAA0B,CAAC,CAAC;AAE3E,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAC5B,KAAK,EAAE,GAAgC,EAAE,KAAkB,EAAE,EAAE;IAC7D,MAAM,eAAe,GAAG,iCAAiC,CAAC;IAC1D,MAAM,EAAE,WAAW,EAAE,qBAAqB,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CACxE,eAAe,CAChB,CAAC;IACF,MAAM,oBAAoB,GAAG,kCAAkC,CAAC;IAChE,MAAM,EACJ,mBAAmB,EACnB,qBAAqB,EACrB,+BAA+B,EAC/B,iCAAiC,EACjC,0BAA0B,EAC1B,2BAA2B,EAC3B,8BAA8B,EAC9B,6BAA6B,EAC7B,8BAA8B,EAC9B,qBAAqB,GACtB,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAEvC,MAAM,iBAAiB,GAAG,YAAY,CAAY,cAAc,EAAE;QAChE,OAAO,EAAE,KAAK;KACf,CAAC,CAAC;IACH,MAAM,6BAA6B,GAAG,YAAY,CAChD,0BAA0B,EAC1B;QACE,OAAO,EAAE,KAAK;KACf,CACF,CAAC;IACF,MAAM,wBAAwB,GAAG,YAAY,CAC3C,qBAAqB,EACrB;QACE,OAAO,EAAE,KAAK;KACf,CACF,CAAC;IACF,MAAM,wBAAwB,GAAG,YAAY,CAC3C,qBAAqB,EACrB;QACE,OAAO,EAAE,KAAK;KACf,CACF,CAAC;IACF,MAAM,6BAA6B,GAAG,YAAY,CAChD,0BAA0B,EAC1B;QACE,OAAO,EAAE,KAAK;KACf,CACF,CAAC;IACF,MAAM,4BAA4B,GAAG,YAAY,CAC/C,yBAAyB,EACzB;QACE,OAAO,EAAE,KAAK;KACf,CACF,CAAC;IACF,MAAM,8BAA8B,GAAG,YAAY,CACjD,2BAA2B,EAC3B;QACE,OAAO,EAAE,KAAK;KACf,CACF,CAAC;IAEF,MAAM,EAAE,OAAO,EAAE,kBAAkB,EAAE,GAAG,MAAM,WAAW,CAAC;QACxD,OAAO,EAAE,GAAG,EAAE;YACZ,OAAO,iBAAiB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACxC,CAAC;QACD,aAAa,EAAE,GAAG,EAAE;YAClB,kDAAkD;QACpD,CAAC;QACD,yBAAyB,EAAE,4BAA4B;QACvD,KAAK,EAAE;YACL,mBAAmB,CAAC;gBAClB,YAAY,EAAE,YAAY,CAAC,qBAAqB,CAAC;aAClD,CAAC;YACF,aAAa,CAAC;gBACZ,YAAY,EAAE,eAAe,CAAC,gBAAgB,CAAC;aAChD,CAAC;YACF,qBAAqB,CAAC,EAAE,YAAY,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC;YACtD,qBAAqB,EAAE;YACvB,qBAAqB,EAAE;SACxB;KACF,CAAC,CAAC;IAEH,MAAM,EAAE,OAAO,EAAE,8BAA8B,EAAE,GAAG,MAAM,WAAW,CAAC;QACpE,OAAO,EAAE,GAAG,EAAE;YACZ,OAAO,6BAA6B,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpD,CAAC;QACD,aAAa,EAAE,GAAG,EAAE;YAClB,kDAAkD;QACpD,CAAC;QACD,yBAAyB,EAAE,4BAA4B;QACvD,WAAW,EAAE,2BAA2B;QACxC,KAAK,EAAE;YACL,+BAA+B,EAAE;YACjC,iCAAiC,EAAE;SACpC;KACF,CAAC,CAAC;IAEH,MAAM,EAAE,OAAO,EAAE,yBAAyB,EAAE,GAAG,MAAM,WAAW,CAAC;QAC/D,OAAO,EAAE,GAAG,EAAE;YACZ,OAAO,wBAAwB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC/C,CAAC;QACD,aAAa,EAAE,GAAG,EAAE;YAClB,kDAAkD;QACpD,CAAC;QACD,yBAAyB,EAAE,4BAA4B;QACvD,WAAW,EAAE,sBAAsB;QACnC,KAAK,EAAE,CAAC,0BAA0B,EAAE,CAAC;KACtC,CAAC,CAAC;IAEH,MAAM,EAAE,OAAO,EAAE,yBAAyB,EAAE,GAAG,MAAM,WAAW,CAAC;QAC/D,OAAO,EAAE,GAAG,EAAE;YACZ,OAAO,wBAAwB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC/C,CAAC;QACD,aAAa,EAAE,GAAG,EAAE;YAClB,kDAAkD;QACpD,CAAC;QACD,yBAAyB,EAAE,4BAA4B;QACvD,WAAW,EAAE,2BAA2B;QACxC,KAAK,EAAE,CAAC,2BAA2B,EAAE,CAAC;KACvC,CAAC,CAAC;IAEH,MAAM,EAAE,OAAO,EAAE,8BAA8B,EAAE,GAAG,MAAM,WAAW,CAAC;QACpE,OAAO,EAAE,GAAG,EAAE;YACZ,OAAO,6BAA6B,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpD,CAAC;QACD,aAAa,EAAE,GAAG,EAAE;YAClB,kDAAkD;QACpD,CAAC;QACD,yBAAyB,EAAE,4BAA4B;QACvD,WAAW,EAAE,4BAA4B;QACzC,KAAK,EAAE,CAAC,8BAA8B,EAAE,CAAC;KAC1C,CAAC,CAAC;IAEH,MAAM,EAAE,OAAO,EAAE,6BAA6B,EAAE,GAAG,MAAM,WAAW,CAAC;QACnE,OAAO,EAAE,GAAG,EAAE;YACZ,OAAO,4BAA4B,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACnD,CAAC;QACD,aAAa,EAAE,GAAG,EAAE;YAClB,kDAAkD;QACpD,CAAC;QACD,yBAAyB,EAAE,4BAA4B;QACvD,WAAW,EAAE,2BAA2B;QACxC,KAAK,EAAE,CAAC,6BAA6B,EAAE,CAAC;KACzC,CAAC,CAAC;IAEH,MAAM,EAAE,OAAO,EAAE,+BAA+B,EAAE,GAAG,MAAM,WAAW,CAAC;QACrE,OAAO,EAAE,GAAG,EAAE;YACZ,OAAO,8BAA8B,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACrD,CAAC;QACD,aAAa,EAAE,GAAG,EAAE;YAClB,kDAAkD;QACpD,CAAC;QACD,yBAAyB,EAAE,4BAA4B;QACvD,WAAW,EAAE,4BAA4B;QACzC,KAAK,EAAE,CAAC,8BAA8B,EAAE,CAAC;KAC1C,CAAC,CAAC;IAEH,MAAM,kBAAkB,EAAE,CAAC;IAC3B,MAAM,8BAA8B,EAAE,CAAC;IACvC,MAAM,yBAAyB,EAAE,CAAC;IAClC,MAAM,yBAAyB,EAAE,CAAC;IAClC,MAAM,8BAA8B,EAAE,CAAC;IACvC,MAAM,6BAA6B,EAAE,CAAC;IACtC,MAAM,+BAA+B,EAAE,CAAC;AAC1C,CAAC,CACF,CAAC"}