@happyvertical/smrt-subscriptions 0.60.14 → 0.60.15
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/AGENTS.md +74 -0
- package/README.md +11 -0
- package/dist/collections/TenantUsageMetricCollection.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +876 -391
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +2 -1
- package/dist/services/entitlement-changes.d.ts +115 -0
- package/dist/services/entitlement-changes.d.ts.map +1 -0
- package/dist/services/hosted-ai-spend.d.ts +182 -0
- package/dist/services/hosted-ai-spend.d.ts.map +1 -0
- package/dist/services/index.d.ts +3 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/subscription-feature-source.d.ts +89 -0
- package/dist/services/subscription-feature-source.d.ts.map +1 -0
- package/dist/services/subscription-resolver.d.ts +34 -1
- package/dist/services/subscription-resolver.d.ts.map +1 -1
- package/dist/smrt-knowledge.json +7 -5
- package/dist/smrt-knowledge.okf.md +3 -2
- package/package.json +6 -5
package/AGENTS.md
CHANGED
|
@@ -86,6 +86,51 @@ that reverted to DECIMAL passes every SQLite suite.
|
|
|
86
86
|
`retainsPaidPeriod`, derived on save from an entitled pre-cancel row.
|
|
87
87
|
- **Recipe `subscriptions.plans`** (`src/recipes.ts`, help in `src/plans.recipe.md`): lists plans, subscriptions, plan versions (read-only, written by `plan-versioning.ts`) and charges (read-only, written by the usage service) for the planner and other catalog hosts. Fields it shows carry `@field({ description })` in plain words, money fields saying "in cents"; keep them when editing the models. Reseller models and pricing rules stay out of it.
|
|
88
88
|
|
|
89
|
+
## Hosted AI spend caps (#4760)
|
|
90
|
+
|
|
91
|
+
`src/services/hosted-ai-spend.ts`. Plans cap platform-paid (`source:
|
|
92
|
+
hosted`) inference with ordinary `PlanThreshold`s on two reserved keys, so
|
|
93
|
+
window, amount and enforcement come from the plan (pinned version included):
|
|
94
|
+
`AI_HOSTED_SPEND_METRIC` (`ai.hosted.spend_micros`, the tenant) and
|
|
95
|
+
`AI_HOSTED_USER_SPEND_METRIC` (`ai.hosted.user_spend_micros`, each user).
|
|
96
|
+
|
|
97
|
+
- `limit` is **integer micro-dollars** (1 USD = 1,000,000; the money rule at
|
|
98
|
+
per-call precision). `block` blocks at or over the cap, `warn` warns,
|
|
99
|
+
`observe` never affects a call; `warningRatio` (default 0.8) warns early;
|
|
100
|
+
a 0 cap blocks every hosted call. A malformed hosted cap (fractional or
|
|
101
|
+
negative limit, unknown window/enforcement) throws
|
|
102
|
+
`HostedAiSpendPolicyError` (the gate fails closed); it never reads as "no
|
|
103
|
+
cap". `resolvePlanThresholds()` returns thresholds unfiltered for this
|
|
104
|
+
reason (the models' `getThresholds()` drop invalid entries) and throws on
|
|
105
|
+
non-array JSON.
|
|
106
|
+
- Spend: `createHostedAiSpendReader(db)` sums `_smrt_ai_usage.estimated_cost`
|
|
107
|
+
(USD, rounded to micro-dollars) by `tenant_id` and `created_at` in the
|
|
108
|
+
cap's window for rows whose `tags` hold `"source":"hosted"` (and
|
|
109
|
+
`"userId":"<id>"` for the per-user cap), as exact, case-sensitive JSON
|
|
110
|
+
fragments (`hostedAiTagFragment()`; `strpos` on the PostgreSQL dialect,
|
|
111
|
+
`instr` elsewhere, never `LIKE`, which folds ASCII case on SQLite and
|
|
112
|
+
would merge `Alice` and `alice`); errors only over-count.
|
|
113
|
+
`operation: 'blocked'` rows and external-agent measurements never count;
|
|
114
|
+
uncosted rows add nothing (give hosted models a cost rate). The `userId`
|
|
115
|
+
tag exists only while the hosted gate's ambient-user resolver is
|
|
116
|
+
registered.
|
|
117
|
+
- `resetsAt`: the calendar window's end; for a blocked `rolling` cap (30
|
|
118
|
+
days), `HostedAiSpendReader.liftsAt()`: one window-function query (newest
|
|
119
|
+
first running `SUM(estimated_cost)`, rounded as `summarize()` rounds)
|
|
120
|
+
returns the row whose expiry first brings the total below the cap, plus
|
|
121
|
+
30 days (null for a 0 cap). A blocked decision names the blocking cap that
|
|
122
|
+
lifts last.
|
|
123
|
+
- `HostedAiSpendEvaluator` (`create({ db })`): plan thresholds via
|
|
124
|
+
`SubscriptionResolver.resolvePlanThresholds()` (entitled terms, no usage
|
|
125
|
+
meters; memoized per tenant for `termsTtlMs`, 30 s, failures evicted,
|
|
126
|
+
`invalidate()`), spend read fresh per call; per-user caps only with a
|
|
127
|
+
user. Errors propagate. smrt-inference's `./gate` consumes it.
|
|
128
|
+
- `resolveEntitlements()` / the tenant usage meter report these keys with
|
|
129
|
+
quantity 0: only the evaluator meters them. The meter's AI summary (and so
|
|
130
|
+
`ai.requests`) skips `operation: 'blocked'` rows. `SpendingPolicy` rows stay the
|
|
131
|
+
billed-charge (cents) policy; hosted AI caps are plan terms because the
|
|
132
|
+
issue's window and amount come from the plan.
|
|
133
|
+
|
|
89
134
|
## Reseller billing (#3059)
|
|
90
135
|
|
|
91
136
|
- Billing ownership is consumed from `smrt-tenancy`'s
|
|
@@ -129,3 +174,32 @@ that reverted to DECIMAL passes every SQLite suite.
|
|
|
129
174
|
current subscription and plan.
|
|
130
175
|
- Subscription UI components should stay provider-neutral and receive actions
|
|
131
176
|
from the host app.
|
|
177
|
+
- **Feature grants as flags (#4761).** `SubscriptionFeatureSource` implements
|
|
178
|
+
`smrt-features`' `FeatureGrantSource` structurally (no dependency either
|
|
179
|
+
way). Build one per request (`SubscriptionFeatureSource.create(options)` or
|
|
180
|
+
`new SubscriptionFeatureSource({ resolver })`; it memoizes grants per
|
|
181
|
+
tenant) and pass it as `grantSource`, or register an app-wide one built with
|
|
182
|
+
`memoize: false` through `registerSubscriptionFeatureSource()`, which writes
|
|
183
|
+
the features slot key `FEATURE_GRANT_SOURCE_SLOT_KEY`. It reads
|
|
184
|
+
`SubscriptionResolver.resolveFeatureGrants()`, which shares the
|
|
185
|
+
version-pinning and entitlement rules of `resolveEntitlements()` but never
|
|
186
|
+
evaluates thresholds, so a flag check reads no usage meters. Missing
|
|
187
|
+
subscription tables (`isMissingSubscriptionTableError`) and no entitled
|
|
188
|
+
subscription report no grants silently; every other error propagates.
|
|
189
|
+
`findGrantingPlan()` names the first active plan by `sortOrder` visible in
|
|
190
|
+
the current context.
|
|
191
|
+
- **Entitlement change hook (#4759).** `src/services/entitlement-changes.ts`.
|
|
192
|
+
The host wraps its billing-webhook write in
|
|
193
|
+
`trackEntitlementChange({ tenantId, resolver }, apply)`: it snapshots
|
|
194
|
+
`resolveFeatureGrants()` (keys plus grant `metadata`, no usage reads)
|
|
195
|
+
before and after, diffs `gained` / `lost` / `changed` (metadata, e.g. a
|
|
196
|
+
plan budget) and calls listeners registered with
|
|
197
|
+
`registerEntitlementChangeListener()` (a `Symbol.for` slot) or passed in.
|
|
198
|
+
Listeners run after `apply`; their failures are returned in `failures`,
|
|
199
|
+
never thrown, and never undo the write, so listeners must be idempotent.
|
|
200
|
+
An `apply` error propagates and notifies nobody. A redelivered webhook
|
|
201
|
+
diffs to no change, so a lost reaction is repaired by the consumer's
|
|
202
|
+
reconcile entry point (hosted inference: `createHostedInferenceReconciler()`
|
|
203
|
+
with `snapshotEntitlements()`), run on redelivery or a schedule. Listeners satisfy the
|
|
204
|
+
structural type (smrt-inference's hosted listener), so this package
|
|
205
|
+
depends on none of them.
|
package/README.md
CHANGED
|
@@ -39,6 +39,17 @@ Create one resolver per request or application unit of work and reuse the
|
|
|
39
39
|
loaded `EntitlementResolutionContext` when several checks need the same
|
|
40
40
|
subscription and plan.
|
|
41
41
|
|
|
42
|
+
### Plan grants as feature flags
|
|
43
|
+
|
|
44
|
+
`SubscriptionFeatureSource` feeds a tenant's plan grants into
|
|
45
|
+
`@happyvertical/smrt-features`, so `FeatureResolver` and its `requireFeature()`
|
|
46
|
+
gate answer from the plan. Build one per request with
|
|
47
|
+
`SubscriptionFeatureSource.create(dbOptions)` and pass it as `grantSource`, or
|
|
48
|
+
register an app-wide one (`memoize: false`) with
|
|
49
|
+
`registerSubscriptionFeatureSource()`. With no subscription tables or no
|
|
50
|
+
entitled subscription it reports no grants. A global feature override still
|
|
51
|
+
outranks a grant (an operator stop), and a tenant override outranks both.
|
|
52
|
+
|
|
42
53
|
## Core model
|
|
43
54
|
|
|
44
55
|
- `SubscriptionPlan` is tenant-scoped by `(tenantId, planKey)` and stores
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TenantUsageMetricCollection.d.ts","sourceRoot":"","sources":["../../src/collections/TenantUsageMetricCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EACV,cAAc,EACd,kBAAkB,EAClB,uBAAuB,EACvB,0BAA0B,EAC1B,qBAAqB,EACrB,YAAY,EACb,MAAM,aAAa,CAAC;AAQrB,qBAAa,2BAA4B,SAAQ,cAAc,CAAC,iBAAiB,CAAC;IAChF,MAAM,CAAC,QAAQ,CAAC,UAAU,2BAAqB;IAEzC,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAmD1E;;;OAGG;IACG,qBAAqB,CACzB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAOzB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,YAAY,CAAC;IAsCrE,mBAAmB,CACvB,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,YAAY,EAAE,CAAC;IAqE1B;;;;;;;;;;;OAWG;IACG,sBAAsB,CAC1B,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"TenantUsageMetricCollection.d.ts","sourceRoot":"","sources":["../../src/collections/TenantUsageMetricCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EACV,cAAc,EACd,kBAAkB,EAClB,uBAAuB,EACvB,0BAA0B,EAC1B,qBAAqB,EACrB,YAAY,EACb,MAAM,aAAa,CAAC;AAQrB,qBAAa,2BAA4B,SAAQ,cAAc,CAAC,iBAAiB,CAAC;IAChF,MAAM,CAAC,QAAQ,CAAC,UAAU,2BAAqB;IAEzC,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAmD1E;;;OAGG;IACG,qBAAqB,CACzB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAOzB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,YAAY,CAAC;IAsCrE,mBAAmB,CACvB,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,YAAY,EAAE,CAAC;IAqE1B;;;;;;;;;;;OAWG;IACG,sBAAsB,CAC1B,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,cAAc,CAAC;CA+B3B"}
|
package/dist/index.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export { enabledFeatureKeys, extractPlanTerms, isEntitlementUpgrade, PLAN_TERM_F
|
|
|
16
16
|
export type { PlanVersionReplacement } from './plan-versioning.js';
|
|
17
17
|
export { SubscriptionPlansRecipe } from './recipes.js';
|
|
18
18
|
export type { AssignPriceBooksInput, AutoTopUpGrant, AutoTopUpHook, AutoTopUpRequest, BillingRelationshipReader, CommercialBillingStorage, CommercialUsageServiceOptions, CustomPricingContext, CustomPricingStrategy, DefinePriceBookPriceInput, DelegatedSpendingPolicyInput, GrantChildCreditInput, GrantCreditInput, PriceBookAssignmentView, PriceBookLeg, PriceUsageOptions, RateUsageOptions, ResellerBillingAction, ResellerBillingErrorCode, ResellerBillingServiceOptions, SpendingDecision, SpendingEvaluationInput, SpendingPolicyEvaluatorExtensions, SpendingPolicyEvaluatorOptions, UsageRating, } from './services/index.js';
|
|
19
|
-
export { assertCommercialBillingStorageSupported, CommercialBillingStorageConfigurationError, CommercialUsageService, evaluateThreshold, evaluateThresholds, ResellerBillingError, ResellerBillingService, SpendingPolicyEvaluator, type SubscriptionPlanReader, type SubscriptionPlanVersionReader, SubscriptionResolver, type SubscriptionResolverReaders, type TenantSubscriptionReader, TenantUsageMeter, UnsupportedCommercialBillingStorageError, type UsageSummaryReader, } from './services/index.js';
|
|
19
|
+
export { AI_HOSTED_SPEND_METRIC, AI_HOSTED_USER_SPEND_METRIC, assertCommercialBillingStorageSupported, CommercialBillingStorageConfigurationError, CommercialUsageService, createHostedAiSpendReader, decideHostedAiSpend, diffEntitlements, ENTITLEMENT_CHANGE_LISTENERS_SLOT_KEY, type EntitlementChange, type EntitlementChangeFailure, type EntitlementChangeListener, type EntitlementChangeOutcome, type EntitlementSnapshot, emptyEntitlementSnapshot, evaluateHostedAiSpendThreshold, evaluateThreshold, evaluateThresholds, FEATURE_GRANT_SOURCE_SLOT_KEY, type GrantingPlanReader, getEntitlementChangeListeners, type HostedAiSpendDecision, type HostedAiSpendEvaluation, HostedAiSpendEvaluator, type HostedAiSpendEvaluatorOptions, type HostedAiSpendPolicy, HostedAiSpendPolicyError, type HostedAiSpendReader, type HostedAiSpendScope, type HostedAiSpendSummary, hasEntitlementChange, hostedAiSpendThresholds, hostedAiTagFragment, isMissingSubscriptionTableError, MICROS_PER_USD, notifyEntitlementChange, ResellerBillingError, ResellerBillingService, registerEntitlementChangeListener, registerSubscriptionFeatureSource, SpendingPolicyEvaluator, type SubscriptionFeatureGrants, SubscriptionFeatureSource, type SubscriptionFeatureSourceOptions, type SubscriptionGrantingPlan, type SubscriptionPlanReader, type SubscriptionPlanVersionReader, SubscriptionResolver, type SubscriptionResolverReaders, snapshotEntitlements, type TenantSubscriptionReader, TenantUsageMeter, type TrackEntitlementChangeOptions, trackEntitlementChange, UnsupportedCommercialBillingStorageError, type UsageSummaryReader, } from './services/index.js';
|
|
20
20
|
export type { AiUsageSummary, BillingInterval, EntitlementResolution, EntitlementResolutionContext, JsonObject, PlanFeatureGrant, PlanTerms, PlanThreshold, PlanVersionPinReason, PricingMode, RecordUsageOptions, Subscriber, SubscriberKind, SubscriptionPlanStatus, SubscriptionPlanVersionOptions, SubscriptionResolverOptions, SubscriptionStatus, SummarizeAiUsageOptions, SummarizeUsageBatchOptions, SummarizeUsageOptions, ThresholdEnforcement, ThresholdEvaluation, ThresholdWindow, UsageMeterOptions, UsageMetricRecord, UsageSummary, UsageWindow, } from './types.js';
|
|
21
21
|
export { assertSubscriberInvariant, getWindowForThreshold, getWindowKey, isValidThreshold, normalizeFeatureGrants, normalizeSubscriber, subscriberToColumns, } from './utils.js';
|
|
22
22
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,wBAAwB,CAAC;AAEhC,OAAO,EACL,0BAA0B,EAC1B,iCAAiC,EACjC,4BAA4B,EAC5B,2BAA2B,GAC5B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,qCAAqC,EACrC,qCAAqC,EACrC,2BAA2B,EAC3B,wCAAwC,GACzC,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACL,+BAA+B,EAC/B,KAAK,uCAAuC,GAC7C,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,aAAa,EACb,eAAe,EACf,aAAa,EACb,cAAc,EACd,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,iBAAiB,EACjB,2BAA2B,EAC3B,YAAY,EACZ,sBAAsB,EACtB,WAAW,EACX,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,SAAS,EACT,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,qBAAqB,EACrB,YAAY,EACZ,sBAAsB,EACtB,cAAc,EACd,wBAAwB,EACxB,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,aAAa,EACb,eAAe,GAChB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,YAAY,EACV,qBAAqB,EACrB,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,yBAAyB,EACzB,wBAAwB,EACxB,6BAA6B,EAC7B,oBAAoB,EACpB,qBAAqB,EACrB,yBAAyB,EACzB,4BAA4B,EAC5B,qBAAqB,EACrB,gBAAgB,EAChB,uBAAuB,EACvB,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,wBAAwB,EACxB,6BAA6B,EAC7B,gBAAgB,EAChB,uBAAuB,EACvB,iCAAiC,EACjC,8BAA8B,EAC9B,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,uCAAuC,EACvC,0CAA0C,EAC1C,sBAAsB,EACtB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,sBAAsB,EACtB,uBAAuB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,6BAA6B,EAClC,oBAAoB,EACpB,KAAK,2BAA2B,EAChC,KAAK,wBAAwB,EAC7B,gBAAgB,EAChB,wCAAwC,EACxC,KAAK,kBAAkB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,cAAc,EACd,eAAe,EACf,qBAAqB,EACrB,4BAA4B,EAC5B,UAAU,EACV,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,oBAAoB,EACpB,WAAW,EACX,kBAAkB,EAClB,UAAU,EACV,cAAc,EACd,sBAAsB,EACtB,8BAA8B,EAC9B,2BAA2B,EAC3B,kBAAkB,EAClB,uBAAuB,EACvB,0BAA0B,EAC1B,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,EACZ,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,YAAY,EACZ,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,wBAAwB,CAAC;AAEhC,OAAO,EACL,0BAA0B,EAC1B,iCAAiC,EACjC,4BAA4B,EAC5B,2BAA2B,GAC5B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,qCAAqC,EACrC,qCAAqC,EACrC,2BAA2B,EAC3B,wCAAwC,GACzC,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACL,+BAA+B,EAC/B,KAAK,uCAAuC,GAC7C,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,aAAa,EACb,eAAe,EACf,aAAa,EACb,cAAc,EACd,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,iBAAiB,EACjB,2BAA2B,EAC3B,YAAY,EACZ,sBAAsB,EACtB,WAAW,EACX,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,SAAS,EACT,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,qBAAqB,EACrB,YAAY,EACZ,sBAAsB,EACtB,cAAc,EACd,wBAAwB,EACxB,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,aAAa,EACb,eAAe,GAChB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,YAAY,EACV,qBAAqB,EACrB,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,yBAAyB,EACzB,wBAAwB,EACxB,6BAA6B,EAC7B,oBAAoB,EACpB,qBAAqB,EACrB,yBAAyB,EACzB,4BAA4B,EAC5B,qBAAqB,EACrB,gBAAgB,EAChB,uBAAuB,EACvB,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,wBAAwB,EACxB,6BAA6B,EAC7B,gBAAgB,EAChB,uBAAuB,EACvB,iCAAiC,EACjC,8BAA8B,EAC9B,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,sBAAsB,EACtB,2BAA2B,EAC3B,uCAAuC,EACvC,0CAA0C,EAC1C,sBAAsB,EACtB,yBAAyB,EACzB,mBAAmB,EACnB,gBAAgB,EAChB,qCAAqC,EACrC,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EACxB,wBAAwB,EACxB,8BAA8B,EAC9B,iBAAiB,EACjB,kBAAkB,EAClB,6BAA6B,EAC7B,KAAK,kBAAkB,EACvB,6BAA6B,EAC7B,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,sBAAsB,EACtB,KAAK,6BAA6B,EAClC,KAAK,mBAAmB,EACxB,wBAAwB,EACxB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,oBAAoB,EACpB,uBAAuB,EACvB,mBAAmB,EACnB,+BAA+B,EAC/B,cAAc,EACd,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACtB,iCAAiC,EACjC,iCAAiC,EACjC,uBAAuB,EACvB,KAAK,yBAAyB,EAC9B,yBAAyB,EACzB,KAAK,gCAAgC,EACrC,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC3B,KAAK,6BAA6B,EAClC,oBAAoB,EACpB,KAAK,2BAA2B,EAChC,oBAAoB,EACpB,KAAK,wBAAwB,EAC7B,gBAAgB,EAChB,KAAK,6BAA6B,EAClC,sBAAsB,EACtB,wCAAwC,EACxC,KAAK,kBAAkB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,cAAc,EACd,eAAe,EACf,qBAAqB,EACrB,4BAA4B,EAC5B,UAAU,EACV,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,oBAAoB,EACpB,WAAW,EACX,kBAAkB,EAClB,UAAU,EACV,cAAc,EACd,sBAAsB,EACtB,8BAA8B,EAC9B,2BAA2B,EAC3B,kBAAkB,EAClB,uBAAuB,EACvB,0BAA0B,EAC1B,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,EACZ,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,YAAY,EACZ,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
|