@getvitops/utils 8.1.0 → 8.2.0-alpha.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.
- package/CHANGELOG.md +264 -8
- package/dist/{adc-BFrzpMHq.d.mts → adc-BoEoogyo.d.mts} +2 -3
- package/dist/adc-BoEoogyo.d.mts.map +1 -0
- package/dist/ads/index.d.mts +50 -17
- package/dist/ads/index.d.mts.map +1 -1
- package/dist/ads/index.mjs +75 -7
- package/dist/ads/index.mjs.map +1 -1
- package/dist/cloudflare-BiK61Oq4.d.mts.map +1 -1
- package/dist/color/index.d.mts +34 -35
- package/dist/color/index.d.mts.map +1 -1
- package/dist/color/index.mjs +3 -1
- package/dist/color/index.mjs.map +1 -1
- package/dist/crm/index.d.mts +288 -0
- package/dist/crm/index.d.mts.map +1 -0
- package/dist/crm/index.mjs +731 -0
- package/dist/crm/index.mjs.map +1 -0
- package/dist/email/index.d.mts +216 -0
- package/dist/email/index.d.mts.map +1 -0
- package/dist/email/index.mjs +331 -0
- package/dist/email/index.mjs.map +1 -0
- package/dist/favicon.d.mts +8 -9
- package/dist/favicon.d.mts.map +1 -1
- package/dist/git/index.d.mts +65 -0
- package/dist/git/index.d.mts.map +1 -0
- package/dist/git/index.mjs +107 -0
- package/dist/git/index.mjs.map +1 -0
- package/dist/hosting/index.d.mts +29 -29
- package/dist/hosting/index.d.mts.map +1 -1
- package/dist/hosting/index.mjs +7 -4
- package/dist/hosting/index.mjs.map +1 -1
- package/dist/identity-BoRddTx3.mjs +35 -0
- package/dist/identity-BoRddTx3.mjs.map +1 -0
- package/dist/index.d.mts +24 -25
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +5 -5
- package/dist/index.mjs.map +1 -1
- package/dist/indexing/index.d.mts +23 -24
- package/dist/indexing/index.d.mts.map +1 -1
- package/dist/media/index.d.mts +24 -24
- package/dist/media/index.d.mts.map +1 -1
- package/dist/media/index.mjs +3 -3
- package/dist/media/index.mjs.map +1 -1
- package/dist/notify/index.d.mts +26 -15
- package/dist/notify/index.d.mts.map +1 -1
- package/dist/notify/index.mjs +50 -20
- package/dist/notify/index.mjs.map +1 -1
- package/dist/onboarding/index.d.mts +10 -141
- package/dist/onboarding/index.d.mts.map +1 -1
- package/dist/onboarding/index.mjs +1 -144
- package/dist/onboarding/index.mjs.map +1 -1
- package/dist/plan-BLKikoOG.mjs +150 -0
- package/dist/plan-BLKikoOG.mjs.map +1 -0
- package/dist/plan-Hq8Pb0Uw.d.mts +133 -0
- package/dist/plan-Hq8Pb0Uw.d.mts.map +1 -0
- package/dist/reviews/index.d.mts +12 -13
- package/dist/reviews/index.d.mts.map +1 -1
- package/dist/schema/index.d.mts +7 -7
- package/dist/schema/index.d.mts.map +1 -1
- package/dist/security/index.d.mts +2 -2
- package/dist/security/index.d.mts.map +1 -1
- package/dist/{token-Bz_-igw-.d.mts → token-DmmoQ7um.d.mts} +6 -3
- package/dist/token-DmmoQ7um.d.mts.map +1 -0
- package/dist/tracking/index.d.mts +43 -17
- package/dist/tracking/index.d.mts.map +1 -1
- package/dist/tracking/index.mjs +2 -1
- package/dist/tracking/index.mjs.map +1 -1
- package/dist/{types-CHHjzRrv.d.mts → types-7ELci8RQ.d.mts} +4 -2
- package/dist/types-7ELci8RQ.d.mts.map +1 -0
- package/package.json +14 -4
- package/dist/adc-BFrzpMHq.d.mts.map +0 -1
- package/dist/token-Bz_-igw-.d.mts.map +0 -1
- package/dist/types-CHHjzRrv.d.mts.map +0 -1
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { t as ConversionEvent } from "../types-7ELci8RQ.mjs";
|
|
2
|
+
//#region src/crm/types.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* The CRM module's own option surface.
|
|
5
|
+
*
|
|
6
|
+
* Deliberately structural rather than `Config['site']['crm']` imported from
|
|
7
|
+
* `@getvitops/generator`: the generator already depends on this package, so
|
|
8
|
+
* importing back would be a cycle. The vocabulary mirrors that block field for
|
|
9
|
+
* field — the same arrangement, and for the same reason, as `IndexingConfig`
|
|
10
|
+
* and `NotifyContext` beside it.
|
|
11
|
+
*
|
|
12
|
+
* Optional fields are written `?: T | undefined` throughout: `exactOptionalPropertyTypes`
|
|
13
|
+
* is on, and these describe a *parsed JSON config* where an absent key and an
|
|
14
|
+
* explicit `undefined` are the same thing.
|
|
15
|
+
*/
|
|
16
|
+
type CrmProvider = 'hubspot' | 'bigin' | 'jobber';
|
|
17
|
+
/** Human-readable label per provider, for the notification email's Delivery
|
|
18
|
+
* line (`describeCrmResult`) and anywhere else a provider must be named
|
|
19
|
+
* without a hand-written ternary. Exhaustive by type — a provider missing
|
|
20
|
+
* here is a compile error, not a mislabelled email. */
|
|
21
|
+
export declare const PROVIDER_LABELS: Record<CrmProvider, string>;
|
|
22
|
+
/** Bigin's data centre — the region a self-client's tokens and API host belong to. */
|
|
23
|
+
type BiginDataCenter = 'com' | 'ca' | 'eu' | 'in' | 'com.au' | 'jp';
|
|
24
|
+
interface HubSpotConfig {
|
|
25
|
+
portalId: string;
|
|
26
|
+
formGuid: string;
|
|
27
|
+
/** Default `na`. Only affects the submissions API host. */
|
|
28
|
+
dataCenter?: 'na' | 'eu' | undefined;
|
|
29
|
+
}
|
|
30
|
+
interface BiginPipelineConfig {
|
|
31
|
+
enabled: boolean;
|
|
32
|
+
subPipeline?: string | undefined;
|
|
33
|
+
stage?: string | undefined;
|
|
34
|
+
}
|
|
35
|
+
interface BiginConfig {
|
|
36
|
+
dataCenter: BiginDataCenter;
|
|
37
|
+
/** Default `Email` — Bigin's own unique field, used for `upsert`'s dedupe. */
|
|
38
|
+
duplicateCheckField?: string | undefined;
|
|
39
|
+
pipeline?: BiginPipelineConfig | undefined;
|
|
40
|
+
}
|
|
41
|
+
interface JobberConfig {
|
|
42
|
+
/**
|
|
43
|
+
* The pinned `X-JOBBER-GRAPHQL-VERSION` date this integration was built and
|
|
44
|
+
* tested against. Overriding it is an escape hatch for a client's app
|
|
45
|
+
* pinned to a different version — not something to reach for casually,
|
|
46
|
+
* since Jobber's schema can change field names between versions.
|
|
47
|
+
*/
|
|
48
|
+
apiVersion?: string | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Look up an existing client by email before creating one (default
|
|
51
|
+
* **false**). Jobber's `clientCreate` has no upsert, so a resubmitting
|
|
52
|
+
* visitor creates a second client unless this runs — but the lookup query's
|
|
53
|
+
* filter shape is not yet verified against a live Jobber schema (see
|
|
54
|
+
* `jobber.ts`'s docblock), so it defaults off rather than risk a wrong
|
|
55
|
+
* query silently blocking a real submission. Set `true` once verified for
|
|
56
|
+
* your account.
|
|
57
|
+
*/
|
|
58
|
+
dedupe?: boolean | undefined;
|
|
59
|
+
note?: {
|
|
60
|
+
/** Attach a best-effort note carrying the message + unmapped
|
|
61
|
+
* attribution (default true). A failure here never downgrades the
|
|
62
|
+
* client write's own success — see `jobber.ts`. */
|
|
63
|
+
enabled?: boolean | undefined;
|
|
64
|
+
} | undefined;
|
|
65
|
+
}
|
|
66
|
+
interface CrmConfig {
|
|
67
|
+
provider: CrmProvider;
|
|
68
|
+
enabled?: boolean | undefined;
|
|
69
|
+
hubspot?: HubSpotConfig | undefined;
|
|
70
|
+
bigin?: BiginConfig | undefined;
|
|
71
|
+
jobber?: JobberConfig | undefined;
|
|
72
|
+
/** Submitted field name → CRM property name. Unmapped fields are dropped, not guessed. */
|
|
73
|
+
fieldMap?: Record<string, string> | undefined;
|
|
74
|
+
/** `_ac` tracking key → CRM property name. Same drop-if-unmapped rule. */
|
|
75
|
+
trackingFields?: Record<string, string> | undefined;
|
|
76
|
+
}
|
|
77
|
+
/** Credentials, never config — always injected by the caller from env vars. */
|
|
78
|
+
interface HubSpotCredentials {
|
|
79
|
+
accessToken: string;
|
|
80
|
+
}
|
|
81
|
+
interface BiginCredentials {
|
|
82
|
+
clientId: string;
|
|
83
|
+
clientSecret: string;
|
|
84
|
+
refreshToken: string;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Jobber's self-client OAuth credential. The refresh token is expected to be
|
|
88
|
+
* static — Refresh Token Rotation must be OFF in the app's Developer Center
|
|
89
|
+
* settings, since a Worker reading a static env var cannot persist a rotated
|
|
90
|
+
* one. See `jobber-token.ts` for the detection when a client's app has it on
|
|
91
|
+
* anyway.
|
|
92
|
+
*/
|
|
93
|
+
interface JobberCredentials {
|
|
94
|
+
clientId: string;
|
|
95
|
+
clientSecret: string;
|
|
96
|
+
refreshToken: string;
|
|
97
|
+
}
|
|
98
|
+
type CrmCredentials = {
|
|
99
|
+
provider: 'hubspot';
|
|
100
|
+
hubspot: HubSpotCredentials;
|
|
101
|
+
} | {
|
|
102
|
+
provider: 'bigin';
|
|
103
|
+
bigin: BiginCredentials;
|
|
104
|
+
} | {
|
|
105
|
+
provider: 'jobber';
|
|
106
|
+
jobber: JobberCredentials;
|
|
107
|
+
};
|
|
108
|
+
/** A channel's decision: on, or off with a stated reason. Mirrors `ChannelPlan`. */
|
|
109
|
+
interface CrmPlan {
|
|
110
|
+
enabled: boolean;
|
|
111
|
+
provider?: CrmProvider | undefined;
|
|
112
|
+
/** Why it's off. Present iff `enabled` is false. */
|
|
113
|
+
skip?: string | undefined;
|
|
114
|
+
}
|
|
115
|
+
/** A provider-neutral record — what a submission maps to, before either executor
|
|
116
|
+
* renders it into that CRM's own request shape. */
|
|
117
|
+
interface CrmRecord {
|
|
118
|
+
firstName?: string | undefined;
|
|
119
|
+
lastName?: string | undefined;
|
|
120
|
+
email?: string | undefined;
|
|
121
|
+
phone?: string | undefined;
|
|
122
|
+
company?: string | undefined;
|
|
123
|
+
message?: string | undefined;
|
|
124
|
+
/** Mapped fields beyond the identity ones above, keyed by the CRM property name. */
|
|
125
|
+
extra: Record<string, string>;
|
|
126
|
+
/** `trackingFields`-mapped attribution, keyed by the CRM property name. Empty
|
|
127
|
+
* when the visitor arrived with no `_ac` cookie — never an error. */
|
|
128
|
+
attribution: Record<string, string>;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* The outcome of one delivery attempt. Never thrown — a CRM write is
|
|
132
|
+
* best-effort and its failure is a fact for the caller to log or notify with,
|
|
133
|
+
* not an exception to propagate into the request that produced the submission.
|
|
134
|
+
*/
|
|
135
|
+
interface CrmResult {
|
|
136
|
+
ok: boolean;
|
|
137
|
+
provider: CrmProvider;
|
|
138
|
+
/** The created/updated record's id, when the CRM returned one. */
|
|
139
|
+
recordId?: string | undefined;
|
|
140
|
+
/** Why it didn't write, or what the classification of the failure was. */
|
|
141
|
+
reason?: string | undefined;
|
|
142
|
+
/** The provider's own error/status code, when it gave one. */
|
|
143
|
+
code?: string | undefined;
|
|
144
|
+
}
|
|
145
|
+
//#endregion
|
|
146
|
+
//#region src/crm/hubspot.d.ts
|
|
147
|
+
interface HubSpotSubmitContext {
|
|
148
|
+
hutk?: string | undefined;
|
|
149
|
+
pageUri?: string | undefined;
|
|
150
|
+
pageName?: string | undefined;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Submit one record to HubSpot's secure forms endpoint.
|
|
154
|
+
*
|
|
155
|
+
* Never throws — a network failure or an unparsable response both come back
|
|
156
|
+
* as a `CrmResult` with `ok: false`, the same "structured result, not an
|
|
157
|
+
* exception" rule `security/turnstile.ts` and `indexing/gsc.ts` follow. Status
|
|
158
|
+
* classification: 401 is a rejected/expired token; 400 naming
|
|
159
|
+
* `MISSING_REQUIRED_FIELDS` or an unrecognised field name is a mapping
|
|
160
|
+
* problem (`fieldMap`/`trackingFields` naming a property that isn't on the
|
|
161
|
+
* form); 429 is the per-portal rate limit.
|
|
162
|
+
*/
|
|
163
|
+
export declare function submitToHubSpot(record: CrmRecord, config: HubSpotConfig, credentials: HubSpotCredentials, context?: HubSpotSubmitContext, fetchImpl?: typeof fetch, timeoutMs?: number): Promise<CrmResult>;
|
|
164
|
+
//#endregion
|
|
165
|
+
//#region src/crm/map.d.ts
|
|
166
|
+
/**
|
|
167
|
+
* Bigin requires `Last_Name`; a form that only asked for a full name or an
|
|
168
|
+
* email needs one derived rather than 400ing on insert.
|
|
169
|
+
*
|
|
170
|
+
* The fallback chain, in order: an explicit last name field → the last space-
|
|
171
|
+
* separated token of a full name → the local part of the email address →
|
|
172
|
+
* refuse, with a stated reason, rather than fabricate a name from nothing.
|
|
173
|
+
* `map.ts` never emits an empty `lastName` for Bigin — `deliverToCrm` reads
|
|
174
|
+
* the refusal and skips the write instead of letting the CRM reject it.
|
|
175
|
+
*/
|
|
176
|
+
export declare function deriveLastName(identity: {
|
|
177
|
+
firstName?: string | undefined;
|
|
178
|
+
lastName?: string | undefined;
|
|
179
|
+
fullName: string;
|
|
180
|
+
email?: string | undefined;
|
|
181
|
+
}): {
|
|
182
|
+
lastName: string;
|
|
183
|
+
} | {
|
|
184
|
+
refusal: string;
|
|
185
|
+
};
|
|
186
|
+
export declare function mapSubmission(event: ConversionEvent, config: CrmConfig): CrmRecord;
|
|
187
|
+
//#endregion
|
|
188
|
+
//#region src/crm/plan.d.ts
|
|
189
|
+
export declare function planCrm(config: CrmConfig | undefined, credentials: CrmCredentials | undefined): CrmPlan;
|
|
190
|
+
//#endregion
|
|
191
|
+
//#region src/crm/bigin.d.ts
|
|
192
|
+
export declare function zohoApiHost(dataCenter: string): string;
|
|
193
|
+
/**
|
|
194
|
+
* Write one record to Bigin. Never throws — a token-exchange failure, a
|
|
195
|
+
* network error and a rejected response all come back as `CrmResult`.
|
|
196
|
+
*/
|
|
197
|
+
export declare function submitToBigin(record: CrmRecord, config: BiginConfig, credentials: BiginCredentials, fetchImpl?: typeof fetch, timeoutMs?: number): Promise<CrmResult>;
|
|
198
|
+
//#endregion
|
|
199
|
+
//#region src/crm/jobber.d.ts
|
|
200
|
+
/**
|
|
201
|
+
* Write one record to Jobber. Never throws — a token-exchange failure, a
|
|
202
|
+
* network error, a top-level GraphQL `errors[]`, and a `userErrors[]` all
|
|
203
|
+
* come back as a `CrmResult` with `ok: false`.
|
|
204
|
+
*/
|
|
205
|
+
export declare function submitToJobber(record: CrmRecord, config: JobberConfig, credentials: JobberCredentials, pageUri: string | undefined, fetchImpl?: typeof fetch, timeoutMs?: number): Promise<CrmResult>;
|
|
206
|
+
//#endregion
|
|
207
|
+
//#region src/crm/zoho-token.d.ts
|
|
208
|
+
export declare function zohoAccountsHost(dataCenter: string): string;
|
|
209
|
+
interface ZohoOAuth {
|
|
210
|
+
clientId: string;
|
|
211
|
+
clientSecret: string;
|
|
212
|
+
refreshToken: string;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Exchange a refresh token for a short-lived Bigin access token, reusing a
|
|
216
|
+
* cached one while it's still valid.
|
|
217
|
+
*
|
|
218
|
+
* `now` is a parameter so cache expiry is testable without a fake clock, the
|
|
219
|
+
* same convention `google/token.ts`'s `googleAccessToken` uses.
|
|
220
|
+
*/
|
|
221
|
+
export declare function zohoAccessToken(oauth: ZohoOAuth, dataCenter: string, fetchImpl?: typeof fetch, now?: number): Promise<string>;
|
|
222
|
+
/** Test-only: clear the module-level cache between cases. */
|
|
223
|
+
export declare function clearZohoTokenCache(): void;
|
|
224
|
+
//#endregion
|
|
225
|
+
//#region src/crm/jobber-token.d.ts
|
|
226
|
+
/**
|
|
227
|
+
* Jobber OAuth2 refresh-token exchange.
|
|
228
|
+
*
|
|
229
|
+
* A plain `application/x-www-form-urlencoded` POST, same shape as Zoho's —
|
|
230
|
+
* see `zoho-token.ts` for why that keeps this Worker-safe (no `node:crypto`,
|
|
231
|
+
* unlike `google/token.ts`'s service-account JWT).
|
|
232
|
+
*
|
|
233
|
+
* One thing Zoho's grant never does: Jobber's Refresh Token Rotation is ON by
|
|
234
|
+
* default for a new app, and when it's on, every exchange returns a *new*
|
|
235
|
+
* refresh token and invalidates the old one. A Worker reading a static env
|
|
236
|
+
* var (`VITOPS_JOBBER_REFRESH_TOKEN`) cannot persist that new value, so this
|
|
237
|
+
* integration requires rotation turned OFF in the app's Developer Center
|
|
238
|
+
* settings — a legitimate setup requirement, since a per-client private app
|
|
239
|
+
* is never published to Jobber's Marketplace (where rotation ON is
|
|
240
|
+
* mandatory). `zohoAccessToken`'s Zoho equivalent has no such failure mode to
|
|
241
|
+
* detect, because Zoho's grant is long-lived by default.
|
|
242
|
+
*
|
|
243
|
+
* Cached per isolate, keyed on the refresh token, with an expiry margin —
|
|
244
|
+
* same rationale as `zoho-token.ts`.
|
|
245
|
+
*/
|
|
246
|
+
interface JobberOAuth {
|
|
247
|
+
clientId: string;
|
|
248
|
+
clientSecret: string;
|
|
249
|
+
refreshToken: string;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Exchange a refresh token for a short-lived Jobber access token, reusing a
|
|
253
|
+
* cached one while it's still valid.
|
|
254
|
+
*
|
|
255
|
+
* Throws a specific, actionable error when Jobber's response carries a
|
|
256
|
+
* *different* refresh token than the one sent — the rotation case above.
|
|
257
|
+
* Without this check, rotation surfaces an hour later as an opaque 401 on a
|
|
258
|
+
* lead that is already lost; with it, the first submission after rotation
|
|
259
|
+
* turns on names the fix.
|
|
260
|
+
*
|
|
261
|
+
* `now` is a parameter so cache expiry is testable without a fake clock, the
|
|
262
|
+
* same convention `zoho-token.ts`'s `zohoAccessToken` uses.
|
|
263
|
+
*/
|
|
264
|
+
export declare function jobberAccessToken(oauth: JobberOAuth, fetchImpl?: typeof fetch, now?: number): Promise<string>;
|
|
265
|
+
/** Test-only: clear the module-level cache between cases. */
|
|
266
|
+
export declare function clearJobberTokenCache(): void;
|
|
267
|
+
//#endregion
|
|
268
|
+
//#region src/crm/index.d.ts
|
|
269
|
+
export interface CrmDeps {
|
|
270
|
+
credentials?: CrmCredentials | undefined;
|
|
271
|
+
fetch?: typeof fetch | undefined;
|
|
272
|
+
timeoutMs?: number | undefined;
|
|
273
|
+
/**
|
|
274
|
+
* The visitor's page context, provider-neutral. HubSpot reads `hutk` (its
|
|
275
|
+
* own session cookie) to stitch the submission to its tracking; Jobber
|
|
276
|
+
* reads `pageUri` for the note body. Not every provider uses every field —
|
|
277
|
+
* an unused one is simply ignored, which is why this is one shape rather
|
|
278
|
+
* than a per-provider option the caller has to pick correctly.
|
|
279
|
+
*/
|
|
280
|
+
pageContext?: HubSpotSubmitContext | undefined;
|
|
281
|
+
}
|
|
282
|
+
export declare function deliverToCrm(event: ConversionEvent, config: CrmConfig | undefined, deps?: CrmDeps): Promise<CrmResult | null>;
|
|
283
|
+
/** A one-line, human-readable delivery note — what `conversion.ts` folds into
|
|
284
|
+
* the notification email's "Delivery" section. */
|
|
285
|
+
export declare function describeCrmResult(result: CrmResult | null): string | null;
|
|
286
|
+
//#endregion
|
|
287
|
+
export type { BiginConfig, BiginCredentials, BiginDataCenter, BiginPipelineConfig, CrmConfig, CrmCredentials, CrmPlan, CrmProvider, CrmRecord, CrmResult, HubSpotConfig, HubSpotCredentials, HubSpotSubmitContext, JobberConfig, JobberCredentials, JobberOAuth };
|
|
288
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/crm/types.ts","../../src/crm/hubspot.ts","../../src/crm/map.ts","../../src/crm/plan.ts","../../src/crm/bigin.ts","../../src/crm/jobber.ts","../../src/crm/zoho-token.ts","../../src/crm/jobber-token.ts","../../src/crm/index.ts"],"mappings":";;;;;;;;;;;;;;;KAcY;;;;;qBAMC,iBAAiB,OAAO;;KAOzB;UAEK;EACf;EACA;;EAEA;;UAGe;EACf;EACA;EACA;;UAGe;EACf,YAAY;;EAEZ;EACA,WAAW;;UAGI;;;;;;;EAOf;;;;;;;;;;EAUA;EACA;;;;IAKM;;;UAKS;EACf,UAAU;EACV;EACA,UAAU;EACV,QAAQ;EACR,SAAS;;EAET,WAAW;;EAEX,iBAAiB;;;UAIF;EACf;;UAGe;EACf;EACA;EACA;;;;;;;;;UAUe;EACf;EACA;EACA;;KAGU;EACN;EAAqB,SAAS;;EAC9B;EAAmB,OAAO;;EAC1B;EAAoB,QAAQ;;;UAGjB;EACf;EACA,WAAW;;EAEX;;;;UAKe;EACf;EACA;EACA;EACA;EACA;EACA;;EAEA,OAAO;;;EAGP,aAAa;;;;;;;UAQE;EACf;EACA,UAAU;;EAEV;;EAEA;;EAEA;;;;UCjHe;EACf;EACA;EACA;;;;;;;;;;;;;wBAcoB,gBACpB,QAAQ,WACR,QAAQ,eACR,aAAa,oBACb,UAAS,sBACT,mBAAkB,OAClB,qBACC,QAAQ;;;;;;;;;;;;;wBCtCK,eAAe;EAC7B;EACA;EACA;EACA;;EACI;;EAAuB;;wBAgDb,cAAc,OAAO,iBAAiB,QAAQ,YAAY;;;wBC/C1D,QACd,QAAQ,uBACR,aAAa,6BACZ;;;wBCba,YAAY;;;;;wBAsBN,cACpB,QAAQ,WACR,QAAQ,aACR,aAAa,kBACb,mBAAkB,OAClB,qBACC,QAAQ;;;;;;;;wBCoJW,eACpB,QAAQ,WACR,QAAQ,cACR,aAAa,mBACb,6BACA,mBAAkB,OAClB,qBACC,QAAQ;;;wBCpLK,iBAAiB;UAehB;EACf;EACA;EACA;;;;;;;;;wBAUoB,gBACpB,OAAO,WACP,oBACA,mBAAkB,OAClB,eACC;;wBAkCa;;;;;;;;;;;;;;;;;;;;;;;UC3DC;EACf;EACA;EACA;;;;;;;;;;;;;;;wBAgBoB,kBACpB,OAAO,aACP,mBAAkB,OAClB,eACC;;wBA8Ca;;;iBCvEC;EACf,cAAc;EACd,eAAe;EACf;;;;;;;;EAQA,cAAc;;wBAGM,aACpB,OAAO,iBACP,QAAQ,uBACR,OAAM,UACL,QAAQ;;;wBAwDK,kBAAkB,QAAQ"}
|