@stackbilt/llm-providers 1.0.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 (59) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +261 -0
  3. package/dist/errors.d.ts +79 -0
  4. package/dist/errors.d.ts.map +1 -0
  5. package/dist/errors.js +183 -0
  6. package/dist/errors.js.map +1 -0
  7. package/dist/factory.d.ts +95 -0
  8. package/dist/factory.d.ts.map +1 -0
  9. package/dist/factory.js +418 -0
  10. package/dist/factory.js.map +1 -0
  11. package/dist/index.d.ts +137 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +263 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/providers/anthropic.d.ts +38 -0
  16. package/dist/providers/anthropic.d.ts.map +1 -0
  17. package/dist/providers/anthropic.js +378 -0
  18. package/dist/providers/anthropic.js.map +1 -0
  19. package/dist/providers/base.d.ts +107 -0
  20. package/dist/providers/base.d.ts.map +1 -0
  21. package/dist/providers/base.js +230 -0
  22. package/dist/providers/base.js.map +1 -0
  23. package/dist/providers/cerebras.d.ts +30 -0
  24. package/dist/providers/cerebras.d.ts.map +1 -0
  25. package/dist/providers/cerebras.js +292 -0
  26. package/dist/providers/cerebras.js.map +1 -0
  27. package/dist/providers/cloudflare.d.ts +47 -0
  28. package/dist/providers/cloudflare.d.ts.map +1 -0
  29. package/dist/providers/cloudflare.js +544 -0
  30. package/dist/providers/cloudflare.js.map +1 -0
  31. package/dist/providers/groq.d.ts +30 -0
  32. package/dist/providers/groq.d.ts.map +1 -0
  33. package/dist/providers/groq.js +222 -0
  34. package/dist/providers/groq.js.map +1 -0
  35. package/dist/providers/openai.d.ts +36 -0
  36. package/dist/providers/openai.d.ts.map +1 -0
  37. package/dist/providers/openai.js +331 -0
  38. package/dist/providers/openai.js.map +1 -0
  39. package/dist/types.d.ts +238 -0
  40. package/dist/types.d.ts.map +1 -0
  41. package/dist/types.js +6 -0
  42. package/dist/types.js.map +1 -0
  43. package/dist/utils/circuit-breaker.d.ts +111 -0
  44. package/dist/utils/circuit-breaker.d.ts.map +1 -0
  45. package/dist/utils/circuit-breaker.js +365 -0
  46. package/dist/utils/circuit-breaker.js.map +1 -0
  47. package/dist/utils/cost-tracker.d.ts +130 -0
  48. package/dist/utils/cost-tracker.d.ts.map +1 -0
  49. package/dist/utils/cost-tracker.js +272 -0
  50. package/dist/utils/cost-tracker.js.map +1 -0
  51. package/dist/utils/credit-ledger.d.ts +161 -0
  52. package/dist/utils/credit-ledger.d.ts.map +1 -0
  53. package/dist/utils/credit-ledger.js +463 -0
  54. package/dist/utils/credit-ledger.js.map +1 -0
  55. package/dist/utils/retry.d.ts +46 -0
  56. package/dist/utils/retry.d.ts.map +1 -0
  57. package/dist/utils/retry.js +125 -0
  58. package/dist/utils/retry.js.map +1 -0
  59. package/package.json +57 -0
@@ -0,0 +1,272 @@
1
+ /**
2
+ * Cost Tracker
3
+ * Tracks and optimizes LLM usage costs across providers
4
+ */
5
+ export class CostTracker {
6
+ providers = new Map();
7
+ config;
8
+ ledger;
9
+ constructor(config = {}, ledger) {
10
+ this.config = {
11
+ inputTokenCost: config.inputTokenCost ?? 0.001, // $0.001 per 1k tokens default
12
+ outputTokenCost: config.outputTokenCost ?? 0.002, // $0.002 per 1k tokens default
13
+ maxMonthlyCost: config.maxMonthlyCost,
14
+ alertThreshold: config.alertThreshold ?? 0.8 // 80% of max cost
15
+ };
16
+ this.ledger = ledger;
17
+ }
18
+ /**
19
+ * Calculate cost for a request
20
+ */
21
+ calculateRequestCost(request, capabilities) {
22
+ const estimatedInputTokens = this.estimateInputTokens(request);
23
+ const estimatedOutputTokens = request.maxTokens || 1000;
24
+ const inputCost = (estimatedInputTokens / 1000) * capabilities.inputTokenCost;
25
+ const outputCost = (estimatedOutputTokens / 1000) * capabilities.outputTokenCost;
26
+ return inputCost + outputCost;
27
+ }
28
+ /**
29
+ * Track actual cost from response
30
+ */
31
+ trackCost(provider, response) {
32
+ if (!response.usage)
33
+ return;
34
+ // Delegate to CreditLedger when present
35
+ if (this.ledger) {
36
+ this.ledger.record(provider, response.model || 'unknown', response.usage.cost || 0, response.usage.inputTokens, response.usage.outputTokens);
37
+ }
38
+ const entry = this.providers.get(provider) || this.createProviderEntry();
39
+ entry.totalCost += response.usage.cost || 0;
40
+ entry.requestCount++;
41
+ entry.inputTokens += response.usage.inputTokens;
42
+ entry.outputTokens += response.usage.outputTokens;
43
+ entry.lastRecordedAt = Date.now();
44
+ this.providers.set(provider, entry);
45
+ // Check cost alerts
46
+ this.checkCostAlerts(provider);
47
+ }
48
+ /**
49
+ * Get the attached CreditLedger (if any)
50
+ */
51
+ getLedger() {
52
+ return this.ledger;
53
+ }
54
+ /**
55
+ * Get total cost across all providers
56
+ */
57
+ getTotalCost() {
58
+ return this.total();
59
+ }
60
+ /**
61
+ * Get cost for specific provider
62
+ */
63
+ getProviderCost(provider) {
64
+ return this.providers.get(provider)?.totalCost || 0;
65
+ }
66
+ /**
67
+ * Get cost breakdown by provider
68
+ */
69
+ getCostBreakdown() {
70
+ const breakdown = {};
71
+ for (const [provider, entry] of this.providers) {
72
+ breakdown[provider] = {
73
+ ...entry,
74
+ cost: entry.totalCost,
75
+ requests: entry.requestCount,
76
+ tokens: {
77
+ input: entry.inputTokens,
78
+ output: entry.outputTokens
79
+ },
80
+ averageCostPerRequest: entry.requestCount > 0 ? entry.totalCost / entry.requestCount : 0
81
+ };
82
+ }
83
+ return breakdown;
84
+ }
85
+ /**
86
+ * Get a provider snapshot aligned with Workers usage reporting.
87
+ */
88
+ breakdown() {
89
+ const snapshot = {};
90
+ for (const [provider, entry] of this.providers) {
91
+ snapshot[provider] = { ...entry };
92
+ }
93
+ return snapshot;
94
+ }
95
+ /**
96
+ * Get total cost across all providers.
97
+ */
98
+ total() {
99
+ let sum = 0;
100
+ for (const entry of this.providers.values()) {
101
+ sum += entry.totalCost;
102
+ }
103
+ return sum;
104
+ }
105
+ /**
106
+ * Get most cost-effective provider for a request
107
+ */
108
+ getMostCostEffectiveProvider(providers, request) {
109
+ let minCost = Infinity;
110
+ let bestProvider = '';
111
+ for (const [provider, capabilities] of Object.entries(providers)) {
112
+ const cost = this.calculateRequestCost(request, capabilities);
113
+ if (cost < minCost) {
114
+ minCost = cost;
115
+ bestProvider = provider;
116
+ }
117
+ }
118
+ return bestProvider;
119
+ }
120
+ /**
121
+ * Check if we're approaching cost limits
122
+ */
123
+ shouldRouteBasedOnCost(provider) {
124
+ if (!this.config.maxMonthlyCost)
125
+ return false;
126
+ const currentCost = this.getProviderCost(provider);
127
+ const threshold = this.config.maxMonthlyCost * (this.config.alertThreshold || 0.8);
128
+ return currentCost >= threshold;
129
+ }
130
+ /**
131
+ * Reset cost tracking (e.g., monthly reset)
132
+ */
133
+ reset() {
134
+ this.providers.clear();
135
+ }
136
+ /**
137
+ * Reset tracking for specific provider
138
+ */
139
+ resetProvider(provider) {
140
+ this.providers.delete(provider);
141
+ }
142
+ /**
143
+ * Drain and reset provider tracking for periodic reporting.
144
+ */
145
+ drain() {
146
+ const snapshot = this.breakdown();
147
+ this.providers.clear();
148
+ return snapshot;
149
+ }
150
+ /**
151
+ * Export cost data for analytics
152
+ */
153
+ exportData() {
154
+ return {
155
+ totalCost: this.getTotalCost(),
156
+ breakdown: this.getCostBreakdown(),
157
+ period: {
158
+ start: Date.now() - 30 * 24 * 60 * 60 * 1000, // 30 days ago
159
+ end: Date.now()
160
+ }
161
+ };
162
+ }
163
+ /**
164
+ * Estimate input tokens from request
165
+ */
166
+ estimateInputTokens(request) {
167
+ // Rough estimation: 1 token ≈ 0.75 words ≈ 4 characters
168
+ let totalChars = 0;
169
+ // Count characters in messages
170
+ for (const message of request.messages) {
171
+ totalChars += message.content.length;
172
+ }
173
+ // Add system prompt if present
174
+ if (request.systemPrompt) {
175
+ totalChars += request.systemPrompt.length;
176
+ }
177
+ // Convert to tokens (rough approximation)
178
+ return Math.ceil(totalChars / 4);
179
+ }
180
+ /**
181
+ * Check for cost alerts
182
+ */
183
+ checkCostAlerts(provider) {
184
+ if (!this.config.maxMonthlyCost || !this.config.alertThreshold)
185
+ return;
186
+ const currentCost = this.getProviderCost(provider);
187
+ const alertThreshold = this.config.maxMonthlyCost * this.config.alertThreshold;
188
+ if (currentCost >= alertThreshold) {
189
+ console.warn(`[CostTracker] Cost alert for ${provider}: $${currentCost.toFixed(4)} (${((currentCost / this.config.maxMonthlyCost) * 100).toFixed(1)}% of limit)`);
190
+ }
191
+ }
192
+ /**
193
+ * Update cost configuration
194
+ */
195
+ updateConfig(config) {
196
+ this.config = { ...this.config, ...config };
197
+ }
198
+ /**
199
+ * Get current configuration
200
+ */
201
+ getConfig() {
202
+ return { ...this.config };
203
+ }
204
+ createProviderEntry() {
205
+ return {
206
+ totalCost: 0,
207
+ requestCount: 0,
208
+ inputTokens: 0,
209
+ outputTokens: 0,
210
+ lastRecordedAt: 0
211
+ };
212
+ }
213
+ }
214
+ /**
215
+ * Default cost tracker instance
216
+ */
217
+ export const defaultCostTracker = new CostTracker();
218
+ /**
219
+ * Cost optimization utilities
220
+ */
221
+ export class CostOptimizer {
222
+ /**
223
+ * Choose optimal provider based on cost and performance
224
+ */
225
+ static chooseOptimalProvider(providers, request, costTracker, performanceWeights = { cost: 0.5, latency: 0.3, quality: 0.2 }) {
226
+ let bestScore = -Infinity;
227
+ let bestProvider = '';
228
+ for (const [provider, capabilities] of Object.entries(providers)) {
229
+ const cost = costTracker.calculateRequestCost(request, capabilities);
230
+ // Normalize cost (lower is better)
231
+ const costScore = 1 / (1 + cost * 1000); // Scale cost for scoring
232
+ // Simple quality score based on model capabilities
233
+ const qualityScore = capabilities.maxContextLength / 100000; // Normalize context length
234
+ // Assume latency score (would be tracked from actual usage)
235
+ const latencyScore = 0.5; // Placeholder
236
+ const totalScore = costScore * performanceWeights.cost +
237
+ latencyScore * performanceWeights.latency +
238
+ qualityScore * performanceWeights.quality;
239
+ if (totalScore > bestScore) {
240
+ bestScore = totalScore;
241
+ bestProvider = provider;
242
+ }
243
+ }
244
+ return bestProvider;
245
+ }
246
+ /**
247
+ * Suggest cost reduction strategies
248
+ */
249
+ static suggestOptimizations(costBreakdown) {
250
+ const suggestions = [];
251
+ const totalCost = Object.values(costBreakdown).reduce((sum, p) => sum + p.cost, 0);
252
+ // Find most expensive provider
253
+ const mostExpensive = Object.entries(costBreakdown)
254
+ .sort(([, a], [, b]) => b.cost - a.cost)[0];
255
+ if (mostExpensive && mostExpensive[1].cost > totalCost * 0.5) {
256
+ suggestions.push(`Consider reducing usage of ${mostExpensive[0]} (${((mostExpensive[1].cost / totalCost) * 100).toFixed(1)}% of total cost)`);
257
+ }
258
+ // Check for high per-request costs
259
+ for (const [provider, data] of Object.entries(costBreakdown)) {
260
+ if (data.averageCostPerRequest > 0.01) { // $0.01 per request
261
+ suggestions.push(`${provider} has high per-request cost ($${(data.averageCostPerRequest).toFixed(4)}). Consider using smaller models or reducing max_tokens.`);
262
+ }
263
+ }
264
+ // Suggest batch processing if many small requests
265
+ const totalRequests = Object.values(costBreakdown).reduce((sum, p) => sum + p.requests, 0);
266
+ if (totalRequests > 1000 && totalCost / totalRequests < 0.001) {
267
+ suggestions.push('Consider batch processing for small requests to reduce overhead costs.');
268
+ }
269
+ return suggestions;
270
+ }
271
+ }
272
+ //# sourceMappingURL=cost-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-tracker.js","sourceRoot":"","sources":["../../src/utils/cost-tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Credit Ledger — single source of truth for LLM spend across the ecosystem.
3
+ *
4
+ * Tracks per-provider, per-model spend with budgets, rate limits, and
5
+ * threshold events. Persistence-agnostic: holds state in memory, serializes
6
+ * via snapshot()/restore() for any storage backend (D1, KV, R2, etc.).
7
+ */
8
+ export type ThresholdTier = 'warning' | 'critical' | 'emergency';
9
+ export type DepletionTier = 'depletion_warning' | 'depletion_critical' | 'depletion_emergency';
10
+ /** Timestamped spend entry for burn rate calculation. */
11
+ export interface SpendEntry {
12
+ timestamp: number;
13
+ provider: string;
14
+ cost: number;
15
+ }
16
+ /** Burn rate over a rolling window. */
17
+ export interface BurnRate {
18
+ costPerHour: number;
19
+ costPerDay: number;
20
+ windowMs: number;
21
+ sampleCount: number;
22
+ }
23
+ /** Projected depletion estimate for a provider. */
24
+ export interface DepletionEstimate {
25
+ remainingBudget: number;
26
+ burnRate: BurnRate;
27
+ projectedDepletionDate: Date | null;
28
+ daysRemaining: number | null;
29
+ }
30
+ /** Windowed spend summary for a provider. */
31
+ export interface SpendSummary {
32
+ provider: string;
33
+ spend: number;
34
+ requestCount: number;
35
+ inputTokens: number;
36
+ outputTokens: number;
37
+ windowMs: number;
38
+ }
39
+ export interface RateLimitWindow {
40
+ used: number;
41
+ limit: number;
42
+ windowStart: number;
43
+ }
44
+ export type RateLimitDimension = 'rpm' | 'rpd' | 'tpm' | 'tpd';
45
+ export interface ModelAccumulator {
46
+ spend: number;
47
+ inputTokens: number;
48
+ outputTokens: number;
49
+ requestCount: number;
50
+ lastRecordedAt: number;
51
+ }
52
+ export interface ProviderAccumulator extends ModelAccumulator {
53
+ models: Record<string, ModelAccumulator>;
54
+ budget: number | null;
55
+ rateLimits: Partial<Record<RateLimitDimension, RateLimitWindow>>;
56
+ }
57
+ export interface BudgetConfig {
58
+ provider: string;
59
+ model?: string;
60
+ monthlyBudget?: number;
61
+ rateLimits?: Partial<Record<RateLimitDimension, number>>;
62
+ }
63
+ export interface ThresholdConfig {
64
+ warning: number;
65
+ critical: number;
66
+ emergency: number;
67
+ }
68
+ export interface ThresholdEvent {
69
+ type: 'threshold_crossed';
70
+ provider: string;
71
+ model?: string;
72
+ tier: ThresholdTier;
73
+ spend: number;
74
+ budget: number;
75
+ utilizationPct: number;
76
+ }
77
+ export interface DepletionEvent {
78
+ type: 'depletion_projected';
79
+ provider: string;
80
+ tier: DepletionTier;
81
+ daysRemaining: number;
82
+ projectedDepletionDate: Date;
83
+ burnRate: BurnRate;
84
+ }
85
+ export type LedgerEvent = ThresholdEvent | DepletionEvent;
86
+ export type LedgerListener = (event: LedgerEvent) => void;
87
+ export interface RateLimitCheck {
88
+ allowed: boolean;
89
+ used: number;
90
+ limit: number;
91
+ }
92
+ export interface CreditLedgerSnapshot {
93
+ version: 1;
94
+ periodStart: number;
95
+ providers: Record<string, {
96
+ spend: number;
97
+ inputTokens: number;
98
+ outputTokens: number;
99
+ requestCount: number;
100
+ lastRecordedAt: number;
101
+ budget: number | null;
102
+ models: Record<string, ModelAccumulator>;
103
+ rateLimits: Partial<Record<RateLimitDimension, RateLimitWindow>>;
104
+ }>;
105
+ thresholds: ThresholdConfig;
106
+ budgets: BudgetConfig[];
107
+ exportedAt: number;
108
+ /** Timestamped spend entries for burn rate calculation. Optional for backward compat. */
109
+ spendHistory?: SpendEntry[];
110
+ }
111
+ export declare class CreditLedger {
112
+ private providers;
113
+ private thresholds;
114
+ private budgets;
115
+ private listeners;
116
+ private periodStart;
117
+ private lastFiredTier;
118
+ private lastFiredDepletionTier;
119
+ private spendHistory;
120
+ private ringBufferSize;
121
+ constructor(config?: {
122
+ thresholds?: Partial<ThresholdConfig>;
123
+ budgets?: BudgetConfig[];
124
+ ringBufferSize?: number;
125
+ });
126
+ record(provider: string, model: string, cost: number, inputTokens: number, outputTokens: number): void;
127
+ setBudget(config: BudgetConfig): void;
128
+ removeBudget(provider: string, model?: string): void;
129
+ remainingBalance(provider: string, model?: string): number | null;
130
+ utilizationPct(provider: string, model?: string): number;
131
+ getProviderAccumulator(provider: string): ProviderAccumulator | undefined;
132
+ getModelAccumulator(provider: string, model: string): ModelAccumulator | undefined;
133
+ totalSpend(): number;
134
+ breakdown(): Record<string, ProviderAccumulator>;
135
+ /**
136
+ * Calculate burn rate for a provider over a rolling window.
137
+ * Default window: 24 hours.
138
+ */
139
+ getBurnRate(provider: string, windowMs?: number): BurnRate;
140
+ /**
141
+ * Project when a provider's budget will be depleted at the current burn rate.
142
+ * Returns null if the provider has no budget or no spend history.
143
+ */
144
+ getDepletionEstimate(provider: string, windowMs?: number): DepletionEstimate | null;
145
+ /**
146
+ * Get windowed spend summary for a provider.
147
+ */
148
+ getSpendSummary(provider: string, windowMs: number): SpendSummary;
149
+ /**
150
+ * Get spend breakdown for all providers over a window.
151
+ */
152
+ getSpendBreakdown(windowMs: number): SpendSummary[];
153
+ checkRateLimit(provider: string, dimension: RateLimitDimension): RateLimitCheck;
154
+ snapshot(): CreditLedgerSnapshot;
155
+ restore(snapshot: CreditLedgerSnapshot): void;
156
+ resetPeriod(): void;
157
+ on(listener: LedgerListener): () => void;
158
+ private getOrCreateProvider;
159
+ private emit;
160
+ }
161
+ //# sourceMappingURL=credit-ledger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credit-ledger.d.ts","sourceRoot":"","sources":["../../src/utils/credit-ledger.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,UAAU,GAAG,WAAW,CAAC;AACjE,MAAM,MAAM,aAAa,GAAG,mBAAmB,GAAG,oBAAoB,GAAG,qBAAqB,CAAC;AAE/F,yDAAyD;AACzD,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,uCAAuC;AACvC,MAAM,WAAW,QAAQ;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,mDAAmD;AACnD,MAAM,WAAW,iBAAiB;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,QAAQ,CAAC;IACnB,sBAAsB,EAAE,IAAI,GAAG,IAAI,CAAC;IACpC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,6CAA6C;AAC7C,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAE/D,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,mBAAoB,SAAQ,gBAAgB;IAC3D,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACzC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,eAAe,CAAC,CAAC,CAAC;CAClE;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC,CAAC;CAC1D;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,mBAAmB,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,qBAAqB,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,aAAa,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,sBAAsB,EAAE,IAAI,CAAC;IAC7B,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,MAAM,WAAW,GAAG,cAAc,GAAG,cAAc,CAAC;AAE1D,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;AAE1D,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAID,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,CAAC,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE;QACxB,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,EAAE,MAAM,CAAC;QACvB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;QACzC,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,eAAe,CAAC,CAAC,CAAC;KAClE,CAAC,CAAC;IACH,UAAU,EAAE,eAAe,CAAC;IAC5B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,yFAAyF;IACzF,YAAY,CAAC,EAAE,UAAU,EAAE,CAAC;CAC7B;AA+DD,qBAAa,YAAY;IACvB,OAAO,CAAC,SAAS,CAA0C;IAC3D,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,SAAS,CAAwB;IACzC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,aAAa,CAAoC;IACzD,OAAO,CAAC,sBAAsB,CAAoC;IAClE,OAAO,CAAC,YAAY,CAAoB;IACxC,OAAO,CAAC,cAAc,CAAS;gBAEnB,MAAM,CAAC,EAAE;QACnB,UAAU,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;QACtC,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;QACzB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB;IAWD,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;IA6FtG,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IA2BrC,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAYpD,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAgBjE,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;IAexD,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAIzE,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAIlF,UAAU,IAAI,MAAM;IAMpB,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC;IAUhD;;;OAGG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,SAA8B,GAAG,QAAQ;IAgB/E;;;OAGG;IACH,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;IAkCnF;;OAEG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY;IAejE;;OAEG;IACH,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE;IAOnD,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,kBAAkB,GAAG,cAAc;IAwB/E,QAAQ,IAAI,oBAAoB;IA0BhC,OAAO,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI;IAmC7C,WAAW,IAAI,IAAI;IAyBnB,EAAE,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,IAAI;IASxC,OAAO,CAAC,mBAAmB;IAqB3B,OAAO,CAAC,IAAI;CASb"}