@agelum/backend 0.1.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 (106) hide show
  1. package/README.md +401 -0
  2. package/dist/client/hooks.d.ts +65 -0
  3. package/dist/client/hooks.d.ts.map +1 -0
  4. package/dist/client/hooks.js +339 -0
  5. package/dist/client/hooks.js.map +1 -0
  6. package/dist/client/index.d.ts +10 -0
  7. package/dist/client/index.d.ts.map +1 -0
  8. package/dist/client/index.js +37 -0
  9. package/dist/client/index.js.map +1 -0
  10. package/dist/client/manager.d.ts +137 -0
  11. package/dist/client/manager.d.ts.map +1 -0
  12. package/dist/client/manager.js +292 -0
  13. package/dist/client/manager.js.map +1 -0
  14. package/dist/client/provider.d.ts +25 -0
  15. package/dist/client/provider.d.ts.map +1 -0
  16. package/dist/client/provider.js +121 -0
  17. package/dist/client/provider.js.map +1 -0
  18. package/dist/client/revalidation.d.ts +101 -0
  19. package/dist/client/revalidation.d.ts.map +1 -0
  20. package/dist/client/revalidation.js +313 -0
  21. package/dist/client/revalidation.js.map +1 -0
  22. package/dist/client/session.d.ts +84 -0
  23. package/dist/client/session.d.ts.map +1 -0
  24. package/dist/client/session.js +186 -0
  25. package/dist/client/session.js.map +1 -0
  26. package/dist/client/sse-client.d.ts +81 -0
  27. package/dist/client/sse-client.d.ts.map +1 -0
  28. package/dist/client/sse-client.js +221 -0
  29. package/dist/client/sse-client.js.map +1 -0
  30. package/dist/client/storage.d.ts +124 -0
  31. package/dist/client/storage.d.ts.map +1 -0
  32. package/dist/client/storage.js +441 -0
  33. package/dist/client/storage.js.map +1 -0
  34. package/dist/client/trpc.d.ts +12 -0
  35. package/dist/client/trpc.d.ts.map +1 -0
  36. package/dist/client/trpc.js +36 -0
  37. package/dist/client/trpc.js.map +1 -0
  38. package/dist/client/types.d.ts +10 -0
  39. package/dist/client/types.d.ts.map +1 -0
  40. package/dist/client/types.js +3 -0
  41. package/dist/client/types.js.map +1 -0
  42. package/dist/client.d.ts +12 -0
  43. package/dist/client.d.ts.map +1 -0
  44. package/dist/client.js +26 -0
  45. package/dist/client.js.map +1 -0
  46. package/dist/config/schema.d.ts +261 -0
  47. package/dist/config/schema.d.ts.map +1 -0
  48. package/dist/config/schema.js +69 -0
  49. package/dist/config/schema.js.map +1 -0
  50. package/dist/core/analyzer.d.ts +15 -0
  51. package/dist/core/analyzer.d.ts.map +1 -0
  52. package/dist/core/analyzer.js +217 -0
  53. package/dist/core/analyzer.js.map +1 -0
  54. package/dist/core/driver.d.ts +7 -0
  55. package/dist/core/driver.d.ts.map +1 -0
  56. package/dist/core/driver.js +261 -0
  57. package/dist/core/driver.js.map +1 -0
  58. package/dist/core/function.d.ts +97 -0
  59. package/dist/core/function.d.ts.map +1 -0
  60. package/dist/core/function.js +252 -0
  61. package/dist/core/function.js.map +1 -0
  62. package/dist/core/sse.d.ts +98 -0
  63. package/dist/core/sse.d.ts.map +1 -0
  64. package/dist/core/sse.js +331 -0
  65. package/dist/core/sse.js.map +1 -0
  66. package/dist/core/types.d.ts +179 -0
  67. package/dist/core/types.d.ts.map +1 -0
  68. package/dist/core/types.js +3 -0
  69. package/dist/core/types.js.map +1 -0
  70. package/dist/examples/teamhub-integration.d.ts +56 -0
  71. package/dist/examples/teamhub-integration.d.ts.map +1 -0
  72. package/dist/examples/teamhub-integration.js +188 -0
  73. package/dist/examples/teamhub-integration.js.map +1 -0
  74. package/dist/index.d.ts +39 -0
  75. package/dist/index.d.ts.map +1 -0
  76. package/dist/index.js +57 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/providers/localStorage.d.ts +13 -0
  79. package/dist/providers/localStorage.d.ts.map +1 -0
  80. package/dist/providers/localStorage.js +64 -0
  81. package/dist/providers/localStorage.js.map +1 -0
  82. package/dist/providers/memory.d.ts +13 -0
  83. package/dist/providers/memory.d.ts.map +1 -0
  84. package/dist/providers/memory.js +40 -0
  85. package/dist/providers/memory.js.map +1 -0
  86. package/dist/providers/redis.d.ts +14 -0
  87. package/dist/providers/redis.d.ts.map +1 -0
  88. package/dist/providers/redis.js +36 -0
  89. package/dist/providers/redis.js.map +1 -0
  90. package/dist/server.d.ts +17 -0
  91. package/dist/server.d.ts.map +1 -0
  92. package/dist/server.js +34 -0
  93. package/dist/server.js.map +1 -0
  94. package/dist/trpc/hooks.d.ts +82 -0
  95. package/dist/trpc/hooks.d.ts.map +1 -0
  96. package/dist/trpc/hooks.js +282 -0
  97. package/dist/trpc/hooks.js.map +1 -0
  98. package/dist/trpc/router.d.ts +75 -0
  99. package/dist/trpc/router.d.ts.map +1 -0
  100. package/dist/trpc/router.js +160 -0
  101. package/dist/trpc/router.js.map +1 -0
  102. package/dist/trpc/types.d.ts +105 -0
  103. package/dist/trpc/types.d.ts.map +1 -0
  104. package/dist/trpc/types.js +6 -0
  105. package/dist/trpc/types.js.map +1 -0
  106. package/package.json +87 -0
package/README.md ADDED
@@ -0,0 +1,401 @@
1
+ # @drizzle/reactive
2
+
3
+ **Zero configuration, maximum intelligence. Reactive everywhere with no boilerplate.**
4
+
5
+ A reactive database library that transforms any Drizzle + tRPC setup into a reactive, real-time system with minimal configuration and zero boilerplate code changes.
6
+
7
+ ## ✨ Features
8
+
9
+ - **🚀 Zero Configuration**: Single config file with just table relations
10
+ - **⚡ Instant Cache**: Shows cached data immediately, revalidates smartly
11
+ - **🔄 Real-time Sync**: Built-in Server-Sent Events for cache invalidation
12
+ - **🎯 Smart Invalidation**: Only invalidates relevant queries based on relations
13
+ - **📱 Offline Ready**: Handles page refresh and session gaps gracefully
14
+ - **🔒 Type Safe**: 100% automatic type safety with tRPC integration
15
+ - **☁️ Vercel Compatible**: Works perfectly with serverless deployment
16
+ - **🧠 Intelligent**: Prioritizes active hooks for better UX
17
+
18
+ ## 🚀 Quick Start
19
+
20
+ ### Installation
21
+
22
+ ```bash
23
+ pnpm add @drizzle/reactive drizzle-orm @trpc/server @trpc/client zod
24
+ ```
25
+
26
+ ## 📖 Core Usage Patterns
27
+
28
+ ### 1. Define Reactive Functions
29
+
30
+ **Key Concept**: Reactive functions work both standalone (server-side) AND via tRPC. The `name` property is crucial for cache keys and tRPC procedures. Use `db.db` to access the underlying Drizzle instance inside handlers.
31
+
32
+ ```typescript
33
+ // server/functions/users.ts
34
+ import { defineReactiveFunction } from '@drizzle/reactive/server'
35
+ import { z } from 'zod'
36
+
37
+ // 1. Define a reactive function with explicit name
38
+ export const getUsers = defineReactiveFunction({
39
+ name: 'users.getAll', // 🔑 This becomes the cache key and tRPC procedure name
40
+
41
+ input: z.object({
42
+ companyId: z.string(), // Generic, not hardcoded organizationId
43
+ limit: z.number().optional().default(50),
44
+ }),
45
+
46
+ dependencies: ['user'], // What tables this function reads from
47
+
48
+ handler: async (input, db) => {
49
+ // Clean signature: (input, db)
50
+ return db.db.query.users.findMany({
51
+ where: (users, { eq }) => eq(users.companyId, input.companyId),
52
+ limit: input.limit,
53
+ })
54
+ },
55
+ })
56
+
57
+ export const createUser = defineReactiveFunction({
58
+ name: 'users.create',
59
+
60
+ input: z.object({
61
+ name: z.string(),
62
+ email: z.string().email(),
63
+ companyId: z.string(),
64
+ }),
65
+
66
+ dependencies: ['user'],
67
+
68
+ handler: async (input, db) => {
69
+ return db.db.insert(users).values(input).returning()
70
+ },
71
+ })
72
+
73
+ export const getUserProfile = defineReactiveFunction({
74
+ name: 'users.profile.getDetailed', // 🏷️ Nested names work perfectly
75
+
76
+ input: z.object({
77
+ userId: z.string(),
78
+ }),
79
+
80
+ dependencies: ['user', 'profile', 'preferences'],
81
+
82
+ handler: async (input, db) => {
83
+ const user = await db.db.query.users.findFirst({
84
+ where: (users, { eq }) => eq(users.id, input.userId),
85
+ with: {
86
+ profile: true,
87
+ preferences: true,
88
+ },
89
+ })
90
+ return user
91
+ },
92
+ })
93
+ ```
94
+
95
+ ### 2. Server-Side Execution (Without tRPC)
96
+
97
+ **Use Case**: Background jobs, API routes, server actions, webhooks, etc.
98
+
99
+ ```typescript
100
+ // server/api/users/route.ts - Next.js API route
101
+ import { getUsers, createUser } from '../functions/users'
102
+ import { db } from '../db'
103
+
104
+ export async function GET(request: Request) {
105
+ const { searchParams } = new URL(request.url)
106
+ const companyId = searchParams.get('companyId')!
107
+
108
+ // ✅ Execute reactive function directly on server
109
+ const users = await getUsers.execute(
110
+ { companyId, limit: 20 },
111
+ db // Your reactive database instance
112
+ )
113
+
114
+ return Response.json({ users })
115
+ }
116
+
117
+ export async function POST(request: Request) {
118
+ const body = await request.json()
119
+
120
+ // ✅ Execute reactive function directly on server
121
+ const newUser = await createUser.execute(body, db)
122
+
123
+ return Response.json({ user: newUser })
124
+ }
125
+ ```
126
+
127
+ ```typescript
128
+ // server/jobs/daily-stats.ts - Background job
129
+ import { getUsers } from '../functions/users'
130
+ import { db } from '../db'
131
+
132
+ export async function generateDailyStats() {
133
+ const companies = await db.db.query.companies.findMany()
134
+
135
+ for (const company of companies) {
136
+ // ✅ Execute reactive function in background job
137
+ const users = await getUsers.execute({ companyId: company.id }, db)
138
+
139
+ // Process stats...
140
+ console.log(`Company ${company.name} has ${users.length} users`)
141
+ }
142
+ }
143
+ ```
144
+
145
+ ### 3. tRPC Integration (Auto-Generated)
146
+
147
+ **Key Feature**: The tRPC router automatically uses the function `name` as the procedure name. Call `.build()` to get the final tRPC router instance.
148
+
149
+ ```typescript
150
+ // server/trpc/router.ts
151
+ import { createReactiveRouter } from '@drizzle/reactive/server'
152
+ import { getUsers, createUser, getUserProfile } from '../functions/users'
153
+ import { db } from '../db'
154
+
155
+ export const appRouter = createReactiveRouter({ db })
156
+ .addQuery(getUsers) // 🔄 Creates procedure: users.getAll
157
+ .addMutation(createUser) // 🔄 Creates procedure: users.create
158
+ .addQuery(getUserProfile) // 🔄 Creates procedure: users.profile.getDetailed
159
+ .build()
160
+
161
+ // ✅ Auto-generated procedures from function names:
162
+ // - users.getAll (query)
163
+ // - users.create (mutation)
164
+ // - users.profile.getDetailed (query)
165
+
166
+ export type AppRouter = typeof appRouter
167
+ ```
168
+
169
+ ### 4. Client-Side Usage (React Hooks)
170
+
171
+ **Zero Configuration**: Just use the tRPC procedure names (which match function names).
172
+
173
+ ```typescript
174
+ // client/components/UserList.tsx
175
+ import { useReactive } from '@drizzle/reactive/client'
176
+
177
+ function UserList({ companyId }: { companyId: string }) {
178
+ // ✅ Uses the function name automatically: 'users.getAll'
179
+ const {
180
+ data: users,
181
+ isStale,
182
+ isLoading,
183
+ } = useReactive('users.getAll', {
184
+ companyId,
185
+ limit: 20,
186
+ })
187
+
188
+ if (isLoading) return <div>Loading...</div>
189
+
190
+ return (
191
+ <div>
192
+ {isStale && <div className="text-orange-500">Syncing...</div>}
193
+
194
+ {users?.map((user) => (
195
+ <UserCard key={user.id} user={user} />
196
+ ))}
197
+ </div>
198
+ )
199
+ }
200
+
201
+ function UserProfile({ userId }: { userId: string }) {
202
+ // ✅ Nested function names work perfectly
203
+ const { data: profile } = useReactive('users.profile.getDetailed', {
204
+ userId,
205
+ })
206
+
207
+ return (
208
+ <div>
209
+ <h1>{profile?.name}</h1>
210
+ <p>{profile?.email}</p>
211
+ {/* Profile details... */}
212
+ </div>
213
+ )
214
+ }
215
+ ```
216
+
217
+ ### 5. Mutations with Real-time Updates
218
+
219
+ ```typescript
220
+ // client/components/CreateUserForm.tsx
221
+ import { useMutation } from '@trpc/react-query'
222
+ import { trpc } from '../trpc'
223
+
224
+ function CreateUserForm({ companyId }: { companyId: string }) {
225
+ const createUserMutation = trpc.users.create.useMutation({
226
+ onSuccess: () => {
227
+ // ✅ Automatic cache invalidation happens via SSE
228
+ // No manual invalidation needed!
229
+ },
230
+ })
231
+
232
+ const handleSubmit = (data: FormData) => {
233
+ createUserMutation.mutate({
234
+ name: data.get('name') as string,
235
+ email: data.get('email') as string,
236
+ companyId,
237
+ })
238
+ }
239
+
240
+ return <form onSubmit={handleSubmit}>{/* Form fields... */}</form>
241
+ }
242
+ ```
243
+
244
+ ## 🏗️ Setup
245
+
246
+ ### 1. Database Configuration
247
+
248
+ ```typescript
249
+ // server/db.ts
250
+ import { createReactiveDb } from '@drizzle/reactive/server'
251
+ import { drizzle } from 'drizzle-orm/postgres-js'
252
+
253
+ const config = {
254
+ relations: {
255
+ // Relations are table names (not column paths)
256
+ // When user table changes, invalidate these queries
257
+ user: ['profile', 'preferences'],
258
+
259
+ // When profile table changes, invalidate these queries
260
+ profile: ['user'],
261
+
262
+ // When preferences table changes, invalidate these queries
263
+ preferences: ['user'],
264
+ },
265
+ }
266
+
267
+ export const db = createReactiveDb(drizzle(pool), config)
268
+ ```
269
+
270
+ ### 2. SSE Endpoint (Next.js)
271
+
272
+ ```typescript
273
+ // app/api/events/route.ts
274
+ import { createSSEStream } from '@drizzle/reactive/server'
275
+
276
+ export async function GET(request: Request) {
277
+ const { searchParams } = new URL(request.url)
278
+ const organizationId = searchParams.get('organizationId')!
279
+
280
+ return createSSEStream(organizationId)
281
+ }
282
+ ```
283
+
284
+ ```typescript
285
+ // app/api/events/ack/route.ts
286
+ // Required for reliable delivery: client acks invalidation events
287
+ import { acknowledgeEvent } from '@drizzle/reactive/server'
288
+
289
+ export async function POST(request: Request) {
290
+ const { eventId } = await request.json()
291
+ acknowledgeEvent(eventId)
292
+ return Response.json({ ok: true })
293
+ }
294
+ ```
295
+
296
+ ### 3. Client Setup
297
+
298
+ ```typescript
299
+ // client/providers/ReactiveProvider.tsx
300
+ // Recommended: use the built-in TrpcReactiveProvider to wire revalidation generically
301
+ 'use client'
302
+ import { TrpcReactiveProvider } from '@drizzle/reactive/client'
303
+ import { createTRPCProxyClient, httpBatchLink } from '@trpc/client'
304
+ import type { AppRouter } from '../server/trpc'
305
+ import { reactiveRelations } from '@your-db-package/reactive-config'
306
+
307
+ const trpcClient = createTRPCProxyClient<AppRouter>({
308
+ links: [httpBatchLink({ url: '/api/trpc' })],
309
+ })
310
+
311
+ export function AppProviders({ children }: { children: React.ReactNode }) {
312
+ const organizationId = 'your-organization-id'
313
+ return (
314
+ <TrpcReactiveProvider
315
+ organizationId={organizationId}
316
+ relations={reactiveRelations}
317
+ trpcClient={trpcClient}
318
+ >
319
+ {children}
320
+ </TrpcReactiveProvider>
321
+ )
322
+ }
323
+
324
+ // Alternatively, you can create your own revalidateFn with createTrpcRevalidateFn
325
+ // and pass it to ReactiveProvider if you need custom behavior.
326
+ ```
327
+
328
+ If you use `ReactiveProvider` directly, make sure to pass a `revalidateFn` for production; the default revalidator returns mock data.
329
+
330
+ ### 4.1 Client Storage & Revalidation Details
331
+
332
+ - The hook composes cache keys as `name::JSON(input)`.
333
+ - LocalStorage is sharded per query to avoid large single entries:
334
+ - Index per organization: `reactive_registry_<orgId>` stores metadata (last revalidated, last server change, connection status).
335
+ - Per-query entry key: `@drizzle/reactive:entry:<orgId>:<hash>` stores `{ name, input, queryKey, data }`.
336
+ - On initial render, cached data (if present) is shown immediately; background revalidation respects a minimum time window to avoid thrashing on quick navigations/refreshes.
337
+ - Errors during revalidation do not overwrite existing cache (no-write-on-error), keeping previously known-good data.
338
+ - Real-time invalidation uses SSE with client acknowledgments and retry; no heartbeats are sent.
339
+
340
+ ### 4.2 Multi-tenant Tips (Optional)
341
+
342
+ - Resolve tenant databases via a main database lookup (e.g., `organization.databaseName`), not by using IDs directly as database names.
343
+ - Read paths should not create databases; handle missing DB (`3D000`) by propagating the error or returning empty based on product policy.
344
+ - Provisioning (create DB/schemas) belongs to explicit setup flows.
345
+
346
+ ## 🎯 Key Benefits Over Manual Approach
347
+
348
+ | Feature | Manual tRPC | @drizzle/reactive |
349
+ | ----------------------- | ---------------------------------- | ------------------------------- |
350
+ | **Function Definition** | Separate function + tRPC procedure | Single `defineReactiveFunction` |
351
+ | **Cache Keys** | Manual generation | Auto from function name |
352
+ | **Invalidation** | Manual `invalidateQueries` | Automatic via relations |
353
+ | **Real-time** | Manual WebSocket setup | Built-in SSE |
354
+ | **Server Execution** | Separate function needed | Same function works everywhere |
355
+ | **Type Safety** | Manual type wiring | 100% automatic |
356
+
357
+ ## 📈 Advanced Usage
358
+
359
+ ### Custom tRPC Procedure Names
360
+
361
+ ```typescript
362
+ // If you need different tRPC names than function names
363
+ const router = createReactiveRouter({ db })
364
+ .addQueryWithName(getUsers, 'getAllUsers') // Custom name
365
+ .addQuery(getUserProfile) // Uses function name: 'users.profile.getDetailed'
366
+ ```
367
+
368
+ ### Background Revalidation
369
+
370
+ ```typescript
371
+ // client/hooks.ts
372
+ function MyComponent() {
373
+ useReactivePriorities([
374
+ 'users.getAll', // High priority (visible)
375
+ 'users.profile.getDetailed', // Medium priority (likely next)
376
+ ])
377
+
378
+ // Component content...
379
+ }
380
+ ```
381
+
382
+ ## 🔧 How It Works
383
+
384
+ 1. **Function Definition**: `defineReactiveFunction` creates functions that work both server-side and via tRPC
385
+ 2. **Name-Based Mapping**: The `name` property becomes both the cache key and tRPC procedure name
386
+ 3. **Auto-Generated Router**: `createReactiveRouter` automatically creates tRPC procedures from functions
387
+ 4. **Smart Caching**: Cache keys are generated from function names and inputs. The React hook composes a key as `name::JSON(input)` internally to uniquely cache and revalidate by input.
388
+ 5. **Real-time Updates**: SSE automatically invalidates affected queries when data changes. No heartbeats are sent; reliability is ensured via client acknowledgments and retry.
389
+ 6. **Session Recovery**: Smart revalidation on page load handles offline scenarios and avoids thrashing with a minimum revalidation window.
390
+
391
+ ## 🤝 Contributing
392
+
393
+ We welcome contributions! Please see our [Contributing Guide](./CONTRIBUTING.md) for details.
394
+
395
+ ## 📄 License
396
+
397
+ MIT License - see [LICENSE](./LICENSE) for details.
398
+
399
+ ---
400
+
401
+ **Made with ❤️ by the TeamHub team**
@@ -0,0 +1,65 @@
1
+ /**
2
+ * React hooks for @drizzle/reactive
3
+ * Provides reactive data access with automatic caching and real-time updates
4
+ */
5
+ import type { ReactiveConfig, InvalidationEvent } from '../core/types';
6
+ /**
7
+ * Initialize the reactive client
8
+ * Call this once at app startup
9
+ */
10
+ export declare function initializeReactiveClient(organizationId: string, config: ReactiveConfig, revalidateFn: (queryKey: string) => Promise<any>): void;
11
+ /**
12
+ * Main hook for reactive data access
13
+ * Automatically handles caching, real-time updates, and revalidation
14
+ */
15
+ export declare function useReactive<T = any>(queryKey: string, input?: any, options?: {
16
+ enabled?: boolean;
17
+ }): {
18
+ data: T | undefined;
19
+ isLoading: boolean;
20
+ isStale: boolean;
21
+ error: Error | null;
22
+ refetch: () => void;
23
+ };
24
+ /**
25
+ * Optional page-level priority hints for better UX
26
+ */
27
+ export declare function useReactivePriorities(priorities: string[]): void;
28
+ /**
29
+ * Hook to get current session statistics
30
+ */
31
+ export declare function useReactiveStats(): any;
32
+ /**
33
+ * Hook to manually trigger cache refresh
34
+ */
35
+ export declare function useReactiveRefresh(): () => Promise<void>;
36
+ /**
37
+ * Hook to get revalidation statistics and performance metrics
38
+ */
39
+ export declare function useRevalidationStats(): any;
40
+ /**
41
+ * Hook to handle invalidation events
42
+ */
43
+ export declare function useReactiveInvalidation(callback: (event: InvalidationEvent) => void): void;
44
+ /**
45
+ * Hook for manual queries with dynamic parameters
46
+ * Unlike useReactive, this hook doesn't auto-fetch and allows changing parameters on each call
47
+ */
48
+ export declare function useReactiveQuery<TData = unknown, TVariables = unknown>(queryKey: string): {
49
+ data: TData | undefined;
50
+ isLoading: boolean;
51
+ error: Error | null;
52
+ refetch: (variables?: TVariables) => Promise<TData>;
53
+ run: (variables: TVariables) => Promise<TData>;
54
+ };
55
+ /**
56
+ * Hook to get connection status
57
+ */
58
+ export declare function useReactiveConnection(): {
59
+ status: "connected" | "connecting" | "disconnected";
60
+ isConnected: boolean;
61
+ isConnecting: boolean;
62
+ isDisconnected: boolean;
63
+ reconnect: () => void;
64
+ };
65
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/client/hooks.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAiBtE;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,cAAc,EACtB,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC,GAC/C,IAAI,CA+BN;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,CAAC,GAAG,GAAG,EACjC,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,GAAG,EACX,OAAO,CAAC,EAAE;IACR,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,GACA;IACD,IAAI,EAAE,CAAC,GAAG,SAAS,CAAA;IACnB,SAAS,EAAE,OAAO,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,CA2JA;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,IAAI,CAYhE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,QAmB/B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,wBAiBjC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,QAiBnC;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,GAC3C,IAAI,CAWN;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,GAAG,OAAO,EAAE,UAAU,GAAG,OAAO,EACpE,QAAQ,EAAE,MAAM,GACf;IACD,IAAI,EAAE,KAAK,GAAG,SAAS,CAAA;IACvB,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB,OAAO,EAAE,CAAC,SAAS,CAAC,EAAE,UAAU,KAAK,OAAO,CAAC,KAAK,CAAC,CAAA;IACnD,GAAG,EAAE,CAAC,SAAS,EAAE,UAAU,KAAK,OAAO,CAAC,KAAK,CAAC,CAAA;CAC/C,CAgEA;AAED;;GAEG;AACH,wBAAgB,qBAAqB;;;;;;EAwBpC"}