@mcp-b/char 0.0.6 → 0.1.1
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/README.md +76 -362
- package/dist/custom-elements.json +2180 -0
- package/dist/display-mode-policy.d.ts +82 -0
- package/dist/display-mode-policy.d.ts.map +1 -0
- package/dist/display-mode-policy.js +87 -0
- package/dist/display-mode-policy.js.map +1 -0
- package/dist/index.d.ts +707 -326
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2374 -15521
- package/dist/index.js.map +1 -1
- package/dist/shell-component.d.ts +379 -0
- package/dist/shell-component.d.ts.map +1 -0
- package/dist/shell-component.js +2508 -0
- package/dist/shell-component.js.map +1 -0
- package/dist/tsdoc-metadata.json +11 -0
- package/dist/utils.d.ts +161 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +393 -0
- package/dist/utils.js.map +1 -0
- package/dist/web-component-standalone.iife.js +1259 -2358
- package/dist/web-component-standalone.iife.js.map +1 -1
- package/dist/web-component.d.ts +381 -180
- package/dist/web-component.d.ts.map +1 -1
- package/dist/web-component.js +1142 -15740
- package/dist/web-component.js.map +1 -1
- package/package.json +23 -115
- package/THIRD_PARTY_NOTICES.md +0 -52
- package/dist/VoiceHandoffPanel-CIFIJSDs.js +0 -244
- package/dist/VoiceHandoffPanel-CIFIJSDs.js.map +0 -1
- package/dist/button-BLnLZvxR.js +0 -105
- package/dist/button-BLnLZvxR.js.map +0 -1
- package/dist/realtimekit.d.ts +0 -15
- package/dist/realtimekit.d.ts.map +0 -1
- package/dist/realtimekit.js +0 -89
- package/dist/realtimekit.js.map +0 -1
- package/dist/styles/globals.css +0 -2
- package/dist/styles.d.ts +0 -2
- package/dist/web-component-standalone.css +0 -37
- package/dist/web-component-standalone.css.map +0 -1
package/dist/utils.js
ADDED
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
/*! @mcp-b/char | Copyright (c) 2025 Kukumis Inc. All rights reserved. | UNLICENSED */
|
|
2
|
+
//#region src/utils/css-resolver.ts
|
|
3
|
+
/**
|
|
4
|
+
* CSS var() Resolver
|
|
5
|
+
*
|
|
6
|
+
* Recursively resolves CSS custom property references (`var(--x, fallback)`)
|
|
7
|
+
* to concrete values using getComputedStyle(). Necessary because `var()`
|
|
8
|
+
* references are not valid across iframe boundaries.
|
|
9
|
+
*
|
|
10
|
+
* Handles nested var() references, fallbacks, and cycle detection.
|
|
11
|
+
*/
|
|
12
|
+
const MAX_CSS_VAR_RESOLVE_DEPTH = 12;
|
|
13
|
+
function findMatchingParen(value, openParenIndex) {
|
|
14
|
+
let depth = 1;
|
|
15
|
+
for (let i = openParenIndex + 1; i < value.length; i++) {
|
|
16
|
+
const char = value[i];
|
|
17
|
+
if (char === "(") depth += 1;
|
|
18
|
+
else if (char === ")") depth -= 1;
|
|
19
|
+
if (depth === 0) return i;
|
|
20
|
+
}
|
|
21
|
+
return -1;
|
|
22
|
+
}
|
|
23
|
+
function splitTopLevelComma(value) {
|
|
24
|
+
let depth = 0;
|
|
25
|
+
for (let i = 0; i < value.length; i++) {
|
|
26
|
+
const char = value[i];
|
|
27
|
+
if (char === "(") depth += 1;
|
|
28
|
+
else if (char === ")") depth = Math.max(0, depth - 1);
|
|
29
|
+
else if (char === "," && depth === 0) return [value.slice(0, i), value.slice(i + 1)];
|
|
30
|
+
}
|
|
31
|
+
return [value, void 0];
|
|
32
|
+
}
|
|
33
|
+
function resolveFallback(fallback, computed, seen, depth) {
|
|
34
|
+
if (!fallback) return void 0;
|
|
35
|
+
return resolveCssValue(fallback, computed, seen, depth + 1) || void 0;
|
|
36
|
+
}
|
|
37
|
+
function resolveCssVariable(variableName, fallback, computed, seen, depth) {
|
|
38
|
+
if (depth > MAX_CSS_VAR_RESOLVE_DEPTH) {
|
|
39
|
+
console.warn(`[Char] CSS variable resolution depth exceeded for "${variableName}". Possible circular reference.`);
|
|
40
|
+
return fallback?.trim();
|
|
41
|
+
}
|
|
42
|
+
if (!variableName.startsWith("--") || seen.has(variableName)) return resolveFallback(fallback, computed, seen, depth);
|
|
43
|
+
const nextSeen = new Set(seen);
|
|
44
|
+
nextSeen.add(variableName);
|
|
45
|
+
const rawValue = computed.getPropertyValue(variableName).trim();
|
|
46
|
+
if (rawValue) {
|
|
47
|
+
const resolvedRaw = resolveCssValue(rawValue, computed, nextSeen, depth + 1);
|
|
48
|
+
if (resolvedRaw) return resolvedRaw;
|
|
49
|
+
}
|
|
50
|
+
return resolveFallback(fallback, computed, seen, depth);
|
|
51
|
+
}
|
|
52
|
+
function resolveCssValue(value, computed, seen, depth = 0) {
|
|
53
|
+
const trimmed = value.trim();
|
|
54
|
+
if (!trimmed || !trimmed.includes("var(") || depth > MAX_CSS_VAR_RESOLVE_DEPTH) return trimmed;
|
|
55
|
+
let cursor = 0;
|
|
56
|
+
let resolved = "";
|
|
57
|
+
let replacedAny = false;
|
|
58
|
+
while (cursor < trimmed.length) {
|
|
59
|
+
const varStart = trimmed.indexOf("var(", cursor);
|
|
60
|
+
if (varStart === -1) {
|
|
61
|
+
resolved += trimmed.slice(cursor);
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
resolved += trimmed.slice(cursor, varStart);
|
|
65
|
+
const openParenIndex = varStart + 3;
|
|
66
|
+
const closeParenIndex = findMatchingParen(trimmed, openParenIndex);
|
|
67
|
+
if (closeParenIndex === -1) {
|
|
68
|
+
resolved += trimmed.slice(varStart);
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
const [rawVariableName, rawFallback] = splitTopLevelComma(trimmed.slice(openParenIndex + 1, closeParenIndex));
|
|
72
|
+
const variableName = rawVariableName.trim();
|
|
73
|
+
const fallback = rawFallback?.trim();
|
|
74
|
+
const replacement = variableName ? resolveCssVariable(variableName, fallback, computed, seen, depth + 1) : void 0;
|
|
75
|
+
if (replacement !== void 0) {
|
|
76
|
+
resolved += replacement;
|
|
77
|
+
replacedAny = true;
|
|
78
|
+
} else resolved += trimmed.slice(varStart, closeParenIndex + 1);
|
|
79
|
+
cursor = closeParenIndex + 1;
|
|
80
|
+
}
|
|
81
|
+
const normalized = resolved.trim();
|
|
82
|
+
if (!replacedAny || !normalized.includes("var(")) return normalized;
|
|
83
|
+
return resolveCssValue(normalized, computed, seen, depth + 1);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
//#endregion
|
|
87
|
+
//#region src/utils/css-sanitizer.ts
|
|
88
|
+
/**
|
|
89
|
+
* Maximum allowed length for CSS custom property values transported to iframe.
|
|
90
|
+
*
|
|
91
|
+
* NOTE: This value and the blocked-token policy intentionally mirror
|
|
92
|
+
* `packages/shared-types/src/schemas/embed-bridge.ts` so validation happens
|
|
93
|
+
* both before transport (host) and at contract parse-time (iframe).
|
|
94
|
+
*
|
|
95
|
+
* CONTROL_CHAR_PATTERN here is intentionally more permissive than
|
|
96
|
+
* embed-bridge.ts: it allows tabs/newlines/CR/FF because
|
|
97
|
+
* normalizeCssFormattingWhitespace converts them to spaces before the
|
|
98
|
+
* control-char check. The iframe-side schema (embed-bridge.ts) uses
|
|
99
|
+
* the stricter pattern as defense-in-depth for values that bypass
|
|
100
|
+
* host-side sanitization.
|
|
101
|
+
*/
|
|
102
|
+
const MAX_CSS_VARIABLE_VALUE_LENGTH = 1024;
|
|
103
|
+
const MAX_HOST_FONT_CSS_LENGTH = 16384;
|
|
104
|
+
const CONTROL_CHAR_PATTERN = /[\u0000-\u0008\u000b\u000e-\u001f\u007f]/u;
|
|
105
|
+
const FONT_RULES_PATTERN = /^(?:\s*@font-face\s*\{[^{}]*\}\s*)+$/iu;
|
|
106
|
+
const CSS_COMMENT_PATTERN = /\/\*[\s\S]*?\*\//g;
|
|
107
|
+
const CSS_FORMATTING_WHITESPACE_PATTERN = /[\t\n\r\f]+/gu;
|
|
108
|
+
/**
|
|
109
|
+
* Normalizes CSS values for dangerous-token scanning.
|
|
110
|
+
* Lowercases and removes CSS comments/whitespace/control chars to catch obfuscation.
|
|
111
|
+
*/
|
|
112
|
+
function normalizeForSecurityScan(value) {
|
|
113
|
+
return value.replace(CSS_COMMENT_PATTERN, "").toLowerCase().replace(/[\s\u0000-\u001f\u007f]+/gu, "");
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Collapses CSS formatting whitespace (tabs, newlines, carriage returns, form feeds)
|
|
117
|
+
* into single spaces. Applied to the output value before trimming, so multiline
|
|
118
|
+
* host-provided values (e.g., font stacks) become single-line without losing
|
|
119
|
+
* meaningful token boundaries. This also ensures split-token obfuscation
|
|
120
|
+
* (e.g., "java\nscript:") is collapsed before the security scan.
|
|
121
|
+
*/
|
|
122
|
+
function normalizeCssFormattingWhitespace(value) {
|
|
123
|
+
return value.replace(CSS_FORMATTING_WHITESPACE_PATTERN, " ");
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Sanitizes host-provided CSS variable values before iframe transport.
|
|
127
|
+
* Returns `undefined` for unsafe or invalid values.
|
|
128
|
+
*
|
|
129
|
+
* @param value - The raw CSS property value.
|
|
130
|
+
* @param variableName - Optional variable name for diagnostic logging.
|
|
131
|
+
*/
|
|
132
|
+
function sanitizeCssVariableValue(value, variableName) {
|
|
133
|
+
const trimmed = normalizeCssFormattingWhitespace(value).trim();
|
|
134
|
+
if (!trimmed) return void 0;
|
|
135
|
+
if (trimmed.length > MAX_CSS_VARIABLE_VALUE_LENGTH) {
|
|
136
|
+
console.warn(`[Char] CSS variable ${variableName ?? "(unknown)"} rejected: value exceeds max length (${trimmed.length} > ${MAX_CSS_VARIABLE_VALUE_LENGTH})`);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (CONTROL_CHAR_PATTERN.test(trimmed)) {
|
|
140
|
+
console.warn(`[Char] CSS variable ${variableName ?? "(unknown)"} rejected: contains control characters`);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const blockedToken = getBlockedCssVariableToken(normalizeForSecurityScan(trimmed));
|
|
144
|
+
if (blockedToken) return warnAndReject(variableName, blockedToken);
|
|
145
|
+
return trimmed;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Sanitizes host-provided font CSS before iframe injection.
|
|
149
|
+
* Only `@font-face` rules are allowed.
|
|
150
|
+
*/
|
|
151
|
+
function sanitizeHostFontCss(fontCss) {
|
|
152
|
+
const trimmed = fontCss.trim();
|
|
153
|
+
if (!trimmed) return void 0;
|
|
154
|
+
if (trimmed.length > MAX_HOST_FONT_CSS_LENGTH) {
|
|
155
|
+
console.warn(`[Char] Host font CSS rejected: value exceeds max length (${trimmed.length} > ${MAX_HOST_FONT_CSS_LENGTH})`);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (CONTROL_CHAR_PATTERN.test(trimmed)) {
|
|
159
|
+
console.warn("[Char] Host font CSS rejected: contains control characters");
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const blockedToken = getBlockedFontToken(normalizeForSecurityScan(trimmed));
|
|
163
|
+
if (blockedToken) {
|
|
164
|
+
console.warn(`[Char] Host font CSS rejected: contains blocked token "${blockedToken}"`);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const withoutComments = trimmed.replace(/\/\*[\s\S]*?\*\//g, "").trim();
|
|
168
|
+
if (!FONT_RULES_PATTERN.test(withoutComments)) {
|
|
169
|
+
console.warn("[Char] Host font CSS rejected: only @font-face rules are allowed");
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
return trimmed;
|
|
173
|
+
}
|
|
174
|
+
function getBlockedCssVariableToken(normalizedValue) {
|
|
175
|
+
if (normalizedValue.includes("javascript:")) return "javascript:";
|
|
176
|
+
if (normalizedValue.includes("vbscript:")) return "vbscript:";
|
|
177
|
+
if (normalizedValue.includes("expression(")) return "expression(";
|
|
178
|
+
if (normalizedValue.includes("@import")) return "@import";
|
|
179
|
+
if (normalizedValue.includes("-moz-binding")) return "-moz-binding";
|
|
180
|
+
if (normalizedValue.includes("url(")) return "url(";
|
|
181
|
+
}
|
|
182
|
+
function getBlockedFontToken(normalizedValue) {
|
|
183
|
+
if (normalizedValue.includes("javascript:")) return "javascript:";
|
|
184
|
+
if (normalizedValue.includes("vbscript:")) return "vbscript:";
|
|
185
|
+
if (normalizedValue.includes("expression(")) return "expression(";
|
|
186
|
+
if (normalizedValue.includes("-moz-binding")) return "-moz-binding";
|
|
187
|
+
}
|
|
188
|
+
function warnAndReject(variableName, blockedToken) {
|
|
189
|
+
console.warn(`[Char] CSS variable ${variableName ?? "(unknown)"} rejected: contains blocked token "${blockedToken}"`);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region src/utils/css-variables.ts
|
|
194
|
+
/**
|
|
195
|
+
* Public CSS variable names for the Char widget.
|
|
196
|
+
*
|
|
197
|
+
* These are the external API — host pages set these to customise the widget.
|
|
198
|
+
* We maintain static lists because `getComputedStyle()` cannot enumerate
|
|
199
|
+
* custom properties.
|
|
200
|
+
*
|
|
201
|
+
* Source of truth:
|
|
202
|
+
* - `src/styles/globals.css` (`--char-*`)
|
|
203
|
+
* - WebMCP ext-apps UI spec (`--color-*`, `--font-*`, etc.)
|
|
204
|
+
*/
|
|
205
|
+
const CHAR_PUBLIC_VARIABLE_NAMES = [
|
|
206
|
+
"--char-color-background",
|
|
207
|
+
"--char-color-foreground",
|
|
208
|
+
"--char-color-card",
|
|
209
|
+
"--char-color-card-foreground",
|
|
210
|
+
"--char-color-popover",
|
|
211
|
+
"--char-color-popover-foreground",
|
|
212
|
+
"--char-color-primary",
|
|
213
|
+
"--char-color-primary-foreground",
|
|
214
|
+
"--char-color-secondary",
|
|
215
|
+
"--char-color-secondary-foreground",
|
|
216
|
+
"--char-color-muted",
|
|
217
|
+
"--char-color-muted-foreground",
|
|
218
|
+
"--char-color-accent",
|
|
219
|
+
"--char-color-accent-foreground",
|
|
220
|
+
"--char-color-destructive",
|
|
221
|
+
"--char-color-destructive-foreground",
|
|
222
|
+
"--char-color-border",
|
|
223
|
+
"--char-color-success",
|
|
224
|
+
"--char-color-warning",
|
|
225
|
+
"--char-color-error",
|
|
226
|
+
"--char-color-input",
|
|
227
|
+
"--char-color-ring",
|
|
228
|
+
"--char-user-bubble-bg",
|
|
229
|
+
"--char-user-bubble-text",
|
|
230
|
+
"--char-assistant-bubble-bg",
|
|
231
|
+
"--char-assistant-bubble-text",
|
|
232
|
+
"--char-composer-bg",
|
|
233
|
+
"--char-composer-border",
|
|
234
|
+
"--char-composer-text",
|
|
235
|
+
"--char-composer-placeholder",
|
|
236
|
+
"--char-composer-button-bg",
|
|
237
|
+
"--char-composer-button-text",
|
|
238
|
+
"--char-tool-bg",
|
|
239
|
+
"--char-tool-border",
|
|
240
|
+
"--char-tool-text",
|
|
241
|
+
"--char-tool-header-bg",
|
|
242
|
+
"--char-tool-approve-bg",
|
|
243
|
+
"--char-tool-approve-text",
|
|
244
|
+
"--char-tool-deny-bg",
|
|
245
|
+
"--char-tool-deny-text",
|
|
246
|
+
"--char-code-bg",
|
|
247
|
+
"--char-code-text",
|
|
248
|
+
"--char-code-header-bg",
|
|
249
|
+
"--char-radius",
|
|
250
|
+
"--char-radius-sm",
|
|
251
|
+
"--char-radius-md",
|
|
252
|
+
"--char-radius-lg",
|
|
253
|
+
"--char-radius-xl",
|
|
254
|
+
"--char-radius-2xl",
|
|
255
|
+
"--char-radius-3xl",
|
|
256
|
+
"--char-radius-full",
|
|
257
|
+
"--char-spacing-unit",
|
|
258
|
+
"--char-font-sans",
|
|
259
|
+
"--char-font-mono",
|
|
260
|
+
"--char-font-size-xs",
|
|
261
|
+
"--char-font-size-sm",
|
|
262
|
+
"--char-font-size-base",
|
|
263
|
+
"--char-font-size-lg",
|
|
264
|
+
"--char-duration-fast",
|
|
265
|
+
"--char-duration-normal",
|
|
266
|
+
"--char-duration-slow",
|
|
267
|
+
"--char-easing-default",
|
|
268
|
+
"--char-easing-spring",
|
|
269
|
+
"--char-z-base",
|
|
270
|
+
"--char-z-content",
|
|
271
|
+
"--char-z-overlay",
|
|
272
|
+
"--char-z-max",
|
|
273
|
+
"--char-shadow-sm",
|
|
274
|
+
"--char-shadow-md",
|
|
275
|
+
"--char-shadow-lg",
|
|
276
|
+
"--char-blur-sm",
|
|
277
|
+
"--char-blur-md",
|
|
278
|
+
"--char-blur-lg"
|
|
279
|
+
];
|
|
280
|
+
const MCP_UI_STYLE_VARIABLE_NAMES = [
|
|
281
|
+
"--color-background-primary",
|
|
282
|
+
"--color-background-secondary",
|
|
283
|
+
"--color-background-tertiary",
|
|
284
|
+
"--color-background-inverse",
|
|
285
|
+
"--color-background-ghost",
|
|
286
|
+
"--color-background-info",
|
|
287
|
+
"--color-background-danger",
|
|
288
|
+
"--color-background-success",
|
|
289
|
+
"--color-background-warning",
|
|
290
|
+
"--color-background-disabled",
|
|
291
|
+
"--color-text-primary",
|
|
292
|
+
"--color-text-secondary",
|
|
293
|
+
"--color-text-tertiary",
|
|
294
|
+
"--color-text-inverse",
|
|
295
|
+
"--color-text-ghost",
|
|
296
|
+
"--color-text-info",
|
|
297
|
+
"--color-text-danger",
|
|
298
|
+
"--color-text-success",
|
|
299
|
+
"--color-text-warning",
|
|
300
|
+
"--color-text-disabled",
|
|
301
|
+
"--color-border-primary",
|
|
302
|
+
"--color-border-secondary",
|
|
303
|
+
"--color-border-tertiary",
|
|
304
|
+
"--color-border-inverse",
|
|
305
|
+
"--color-border-ghost",
|
|
306
|
+
"--color-border-info",
|
|
307
|
+
"--color-border-danger",
|
|
308
|
+
"--color-border-success",
|
|
309
|
+
"--color-border-warning",
|
|
310
|
+
"--color-border-disabled",
|
|
311
|
+
"--color-ring-primary",
|
|
312
|
+
"--color-ring-secondary",
|
|
313
|
+
"--color-ring-inverse",
|
|
314
|
+
"--color-ring-info",
|
|
315
|
+
"--color-ring-danger",
|
|
316
|
+
"--color-ring-success",
|
|
317
|
+
"--color-ring-warning",
|
|
318
|
+
"--font-sans",
|
|
319
|
+
"--font-mono",
|
|
320
|
+
"--font-weight-normal",
|
|
321
|
+
"--font-weight-medium",
|
|
322
|
+
"--font-weight-semibold",
|
|
323
|
+
"--font-weight-bold",
|
|
324
|
+
"--font-text-xs-size",
|
|
325
|
+
"--font-text-sm-size",
|
|
326
|
+
"--font-text-md-size",
|
|
327
|
+
"--font-text-lg-size",
|
|
328
|
+
"--font-heading-xs-size",
|
|
329
|
+
"--font-heading-sm-size",
|
|
330
|
+
"--font-heading-md-size",
|
|
331
|
+
"--font-heading-lg-size",
|
|
332
|
+
"--font-heading-xl-size",
|
|
333
|
+
"--font-heading-2xl-size",
|
|
334
|
+
"--font-heading-3xl-size",
|
|
335
|
+
"--font-text-xs-line-height",
|
|
336
|
+
"--font-text-sm-line-height",
|
|
337
|
+
"--font-text-md-line-height",
|
|
338
|
+
"--font-text-lg-line-height",
|
|
339
|
+
"--font-heading-xs-line-height",
|
|
340
|
+
"--font-heading-sm-line-height",
|
|
341
|
+
"--font-heading-md-line-height",
|
|
342
|
+
"--font-heading-lg-line-height",
|
|
343
|
+
"--font-heading-xl-line-height",
|
|
344
|
+
"--font-heading-2xl-line-height",
|
|
345
|
+
"--font-heading-3xl-line-height",
|
|
346
|
+
"--border-radius-xs",
|
|
347
|
+
"--border-radius-sm",
|
|
348
|
+
"--border-radius-md",
|
|
349
|
+
"--border-radius-lg",
|
|
350
|
+
"--border-radius-xl",
|
|
351
|
+
"--border-radius-full",
|
|
352
|
+
"--border-width-regular",
|
|
353
|
+
"--shadow-hairline",
|
|
354
|
+
"--shadow-sm",
|
|
355
|
+
"--shadow-md",
|
|
356
|
+
"--shadow-lg"
|
|
357
|
+
];
|
|
358
|
+
const CHAR_CSS_VARIABLE_NAMES = [...CHAR_PUBLIC_VARIABLE_NAMES, ...MCP_UI_STYLE_VARIABLE_NAMES];
|
|
359
|
+
|
|
360
|
+
//#endregion
|
|
361
|
+
//#region src/utils/host-context-merge.ts
|
|
362
|
+
function mergeStyles(current, patch) {
|
|
363
|
+
if (!patch) return current;
|
|
364
|
+
return {
|
|
365
|
+
...current,
|
|
366
|
+
...patch,
|
|
367
|
+
variables: patch.variables ?? current?.variables,
|
|
368
|
+
fonts: patch.fonts ?? current?.fonts
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
function shallowMerge(current, patch) {
|
|
372
|
+
if (!patch) return current;
|
|
373
|
+
return {
|
|
374
|
+
...current,
|
|
375
|
+
...patch
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
function mergeHostContext(current, patch) {
|
|
379
|
+
const previous = current ?? {};
|
|
380
|
+
return {
|
|
381
|
+
...previous,
|
|
382
|
+
...patch,
|
|
383
|
+
styles: mergeStyles(previous.styles, patch.styles),
|
|
384
|
+
containerDimensions: shallowMerge(previous.containerDimensions, patch.containerDimensions),
|
|
385
|
+
deviceCapabilities: shallowMerge(previous.deviceCapabilities, patch.deviceCapabilities),
|
|
386
|
+
safeAreaInsets: shallowMerge(previous.safeAreaInsets, patch.safeAreaInsets),
|
|
387
|
+
hostCapabilities: shallowMerge(previous.hostCapabilities, patch.hostCapabilities)
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
//#endregion
|
|
392
|
+
export { CHAR_CSS_VARIABLE_NAMES, MAX_CSS_VARIABLE_VALUE_LENGTH, MAX_CSS_VAR_RESOLVE_DEPTH, MAX_HOST_FONT_CSS_LENGTH, findMatchingParen, mergeHostContext, mergeStyles, resolveCssValue, resolveCssVariable, resolveFallback, sanitizeCssVariableValue, sanitizeHostFontCss, shallowMerge, splitTopLevelComma };
|
|
393
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","names":[],"sources":["../src/utils/css-resolver.ts","../src/utils/css-sanitizer.ts","../src/utils/css-variables.ts","../src/utils/host-context-merge.ts"],"sourcesContent":["/**\n * CSS var() Resolver\n *\n * Recursively resolves CSS custom property references (`var(--x, fallback)`)\n * to concrete values using getComputedStyle(). Necessary because `var()`\n * references are not valid across iframe boundaries.\n *\n * Handles nested var() references, fallbacks, and cycle detection.\n */\n\nexport const MAX_CSS_VAR_RESOLVE_DEPTH = 12\n\nexport function findMatchingParen(value: string, openParenIndex: number): number {\n\tlet depth = 1\n\tfor (let i = openParenIndex + 1; i < value.length; i++) {\n\t\tconst char = value[i]\n\t\tif (char === '(') depth += 1\n\t\telse if (char === ')') depth -= 1\n\t\tif (depth === 0) return i\n\t}\n\treturn -1\n}\n\nexport function splitTopLevelComma(value: string): [string, string | undefined] {\n\tlet depth = 0\n\tfor (let i = 0; i < value.length; i++) {\n\t\tconst char = value[i]\n\t\tif (char === '(') depth += 1\n\t\telse if (char === ')') depth = Math.max(0, depth - 1)\n\t\telse if (char === ',' && depth === 0) return [value.slice(0, i), value.slice(i + 1)]\n\t}\n\treturn [value, undefined]\n}\n\nexport function resolveFallback(\n\tfallback: string | undefined,\n\tcomputed: CSSStyleDeclaration,\n\tseen: Set<string>,\n\tdepth: number,\n): string | undefined {\n\tif (!fallback) return undefined\n\treturn resolveCssValue(fallback, computed, seen, depth + 1) || undefined\n}\n\nexport function resolveCssVariable(\n\tvariableName: string,\n\tfallback: string | undefined,\n\tcomputed: CSSStyleDeclaration,\n\tseen: Set<string>,\n\tdepth: number,\n): string | undefined {\n\tif (depth > MAX_CSS_VAR_RESOLVE_DEPTH) {\n\t\tconsole.warn(`[Char] CSS variable resolution depth exceeded for \"${variableName}\". Possible circular reference.`)\n\t\treturn fallback?.trim()\n\t}\n\n\tif (!variableName.startsWith('--') || seen.has(variableName)) {\n\t\treturn resolveFallback(fallback, computed, seen, depth)\n\t}\n\n\tconst nextSeen = new Set(seen)\n\tnextSeen.add(variableName)\n\n\tconst rawValue = computed.getPropertyValue(variableName).trim()\n\tif (rawValue) {\n\t\tconst resolvedRaw = resolveCssValue(rawValue, computed, nextSeen, depth + 1)\n\t\tif (resolvedRaw) return resolvedRaw\n\t}\n\n\treturn resolveFallback(fallback, computed, seen, depth)\n}\n\nexport function resolveCssValue(\n\tvalue: string,\n\tcomputed: CSSStyleDeclaration,\n\tseen: Set<string>,\n\tdepth = 0,\n): string {\n\tconst trimmed = value.trim()\n\tif (!trimmed || !trimmed.includes('var(') || depth > MAX_CSS_VAR_RESOLVE_DEPTH) {\n\t\treturn trimmed\n\t}\n\n\tlet cursor = 0\n\tlet resolved = ''\n\tlet replacedAny = false\n\n\twhile (cursor < trimmed.length) {\n\t\tconst varStart = trimmed.indexOf('var(', cursor)\n\t\tif (varStart === -1) {\n\t\t\tresolved += trimmed.slice(cursor)\n\t\t\tbreak\n\t\t}\n\n\t\tresolved += trimmed.slice(cursor, varStart)\n\n\t\tconst openParenIndex = varStart + 3\n\t\tconst closeParenIndex = findMatchingParen(trimmed, openParenIndex)\n\t\tif (closeParenIndex === -1) {\n\t\t\tresolved += trimmed.slice(varStart)\n\t\t\tbreak\n\t\t}\n\n\t\tconst rawArgs = trimmed.slice(openParenIndex + 1, closeParenIndex)\n\t\tconst [rawVariableName, rawFallback] = splitTopLevelComma(rawArgs)\n\t\tconst variableName = rawVariableName.trim()\n\t\tconst fallback = rawFallback?.trim()\n\n\t\tconst replacement = variableName\n\t\t\t? resolveCssVariable(variableName, fallback, computed, seen, depth + 1)\n\t\t\t: undefined\n\n\t\tif (replacement !== undefined) {\n\t\t\tresolved += replacement\n\t\t\treplacedAny = true\n\t\t} else {\n\t\t\tresolved += trimmed.slice(varStart, closeParenIndex + 1)\n\t\t}\n\n\t\tcursor = closeParenIndex + 1\n\t}\n\n\tconst normalized = resolved.trim()\n\tif (!replacedAny || !normalized.includes('var(')) {\n\t\treturn normalized\n\t}\n\n\treturn resolveCssValue(normalized, computed, seen, depth + 1)\n}\n","/**\n * Maximum allowed length for CSS custom property values transported to iframe.\n *\n * NOTE: This value and the blocked-token policy intentionally mirror\n * `packages/shared-types/src/schemas/embed-bridge.ts` so validation happens\n * both before transport (host) and at contract parse-time (iframe).\n *\n * CONTROL_CHAR_PATTERN here is intentionally more permissive than\n * embed-bridge.ts: it allows tabs/newlines/CR/FF because\n * normalizeCssFormattingWhitespace converts them to spaces before the\n * control-char check. The iframe-side schema (embed-bridge.ts) uses\n * the stricter pattern as defense-in-depth for values that bypass\n * host-side sanitization.\n */\nexport const MAX_CSS_VARIABLE_VALUE_LENGTH = 1024\nexport const MAX_HOST_FONT_CSS_LENGTH = 16_384\n\nconst CONTROL_CHAR_PATTERN = /[\\u0000-\\u0008\\u000b\\u000e-\\u001f\\u007f]/u\nconst FONT_RULES_PATTERN = /^(?:\\s*@font-face\\s*\\{[^{}]*\\}\\s*)+$/iu\nconst CSS_COMMENT_PATTERN = /\\/\\*[\\s\\S]*?\\*\\//g\nconst CSS_FORMATTING_WHITESPACE_PATTERN = /[\\t\\n\\r\\f]+/gu\n\n/**\n * Normalizes CSS values for dangerous-token scanning.\n * Lowercases and removes CSS comments/whitespace/control chars to catch obfuscation.\n */\nfunction normalizeForSecurityScan(value: string): string {\n\tconst withoutComments = value.replace(CSS_COMMENT_PATTERN, '')\n\treturn withoutComments.toLowerCase().replace(/[\\s\\u0000-\\u001f\\u007f]+/gu, '')\n}\n\n/**\n * Collapses CSS formatting whitespace (tabs, newlines, carriage returns, form feeds)\n * into single spaces. Applied to the output value before trimming, so multiline\n * host-provided values (e.g., font stacks) become single-line without losing\n * meaningful token boundaries. This also ensures split-token obfuscation\n * (e.g., \"java\\nscript:\") is collapsed before the security scan.\n */\nfunction normalizeCssFormattingWhitespace(value: string): string {\n\treturn value.replace(CSS_FORMATTING_WHITESPACE_PATTERN, ' ')\n}\n\n/**\n * Sanitizes host-provided CSS variable values before iframe transport.\n * Returns `undefined` for unsafe or invalid values.\n *\n * @param value - The raw CSS property value.\n * @param variableName - Optional variable name for diagnostic logging.\n */\nexport function sanitizeCssVariableValue(value: string, variableName?: string): string | undefined {\n\tconst trimmed = normalizeCssFormattingWhitespace(value).trim()\n\tif (!trimmed) return undefined\n\tif (trimmed.length > MAX_CSS_VARIABLE_VALUE_LENGTH) {\n\t\tconsole.warn(`[Char] CSS variable ${variableName ?? '(unknown)'} rejected: value exceeds max length (${trimmed.length} > ${MAX_CSS_VARIABLE_VALUE_LENGTH})`)\n\t\treturn undefined\n\t}\n\tif (CONTROL_CHAR_PATTERN.test(trimmed)) {\n\t\tconsole.warn(`[Char] CSS variable ${variableName ?? '(unknown)'} rejected: contains control characters`)\n\t\treturn undefined\n\t}\n\n\tconst normalized = normalizeForSecurityScan(trimmed)\n\tconst blockedToken = getBlockedCssVariableToken(normalized)\n\tif (blockedToken) return warnAndReject(variableName, blockedToken)\n\n\treturn trimmed\n}\n\n/**\n * Sanitizes host-provided font CSS before iframe injection.\n * Only `@font-face` rules are allowed.\n */\nexport function sanitizeHostFontCss(fontCss: string): string | undefined {\n\tconst trimmed = fontCss.trim()\n\tif (!trimmed) return undefined\n\tif (trimmed.length > MAX_HOST_FONT_CSS_LENGTH) {\n\t\tconsole.warn(`[Char] Host font CSS rejected: value exceeds max length (${trimmed.length} > ${MAX_HOST_FONT_CSS_LENGTH})`)\n\t\treturn undefined\n\t}\n\tif (CONTROL_CHAR_PATTERN.test(trimmed)) {\n\t\tconsole.warn('[Char] Host font CSS rejected: contains control characters')\n\t\treturn undefined\n\t}\n\n\tconst normalized = normalizeForSecurityScan(trimmed)\n\tconst blockedToken = getBlockedFontToken(normalized)\n\tif (blockedToken) {\n\t\tconsole.warn(`[Char] Host font CSS rejected: contains blocked token \"${blockedToken}\"`)\n\t\treturn undefined\n\t}\n\n\tconst withoutComments = trimmed.replace(/\\/\\*[\\s\\S]*?\\*\\//g, '').trim()\n\tif (!FONT_RULES_PATTERN.test(withoutComments)) {\n\t\tconsole.warn('[Char] Host font CSS rejected: only @font-face rules are allowed')\n\t\treturn undefined\n\t}\n\n\treturn trimmed\n}\n\nfunction getBlockedCssVariableToken(normalizedValue: string): string | undefined {\n\tif (normalizedValue.includes('javascript:')) return 'javascript:'\n\tif (normalizedValue.includes('vbscript:')) return 'vbscript:'\n\tif (normalizedValue.includes('expression(')) return 'expression('\n\tif (normalizedValue.includes('@import')) return '@import'\n\tif (normalizedValue.includes('-moz-binding')) return '-moz-binding'\n\tif (normalizedValue.includes('url(')) return 'url('\n\treturn undefined\n}\n\nfunction getBlockedFontToken(normalizedValue: string): string | undefined {\n\tif (normalizedValue.includes('javascript:')) return 'javascript:'\n\tif (normalizedValue.includes('vbscript:')) return 'vbscript:'\n\tif (normalizedValue.includes('expression(')) return 'expression('\n\tif (normalizedValue.includes('-moz-binding')) return '-moz-binding'\n\treturn undefined\n}\n\nfunction warnAndReject(variableName: string | undefined, blockedToken: string): undefined {\n\tconsole.warn(`[Char] CSS variable ${variableName ?? '(unknown)'} rejected: contains blocked token \"${blockedToken}\"`)\n\treturn undefined\n}\n","/**\n * Public CSS variable names for the Char widget.\n *\n * These are the external API — host pages set these to customise the widget.\n * We maintain static lists because `getComputedStyle()` cannot enumerate\n * custom properties.\n *\n * Source of truth:\n * - `src/styles/globals.css` (`--char-*`)\n * - WebMCP ext-apps UI spec (`--color-*`, `--font-*`, etc.)\n */\n\nconst CHAR_PUBLIC_VARIABLE_NAMES = [\n\t// Colors - Core\n\t'--char-color-background',\n\t'--char-color-foreground',\n\t'--char-color-card',\n\t'--char-color-card-foreground',\n\t'--char-color-popover',\n\t'--char-color-popover-foreground',\n\t'--char-color-primary',\n\t'--char-color-primary-foreground',\n\t'--char-color-secondary',\n\t'--char-color-secondary-foreground',\n\t'--char-color-muted',\n\t'--char-color-muted-foreground',\n\t'--char-color-accent',\n\t'--char-color-accent-foreground',\n\t'--char-color-destructive',\n\t'--char-color-destructive-foreground',\n\t'--char-color-border',\n\n\t// Colors - Semantic\n\t'--char-color-success',\n\t'--char-color-warning',\n\t'--char-color-error',\n\n\t// Colors - Derived\n\t'--char-color-input',\n\t'--char-color-ring',\n\n\t// Message Bubbles\n\t'--char-user-bubble-bg',\n\t'--char-user-bubble-text',\n\t'--char-assistant-bubble-bg',\n\t'--char-assistant-bubble-text',\n\n\t// Composer\n\t'--char-composer-bg',\n\t'--char-composer-border',\n\t'--char-composer-text',\n\t'--char-composer-placeholder',\n\t'--char-composer-button-bg',\n\t'--char-composer-button-text',\n\n\t// Tool Cards\n\t'--char-tool-bg',\n\t'--char-tool-border',\n\t'--char-tool-text',\n\t'--char-tool-header-bg',\n\t'--char-tool-approve-bg',\n\t'--char-tool-approve-text',\n\t'--char-tool-deny-bg',\n\t'--char-tool-deny-text',\n\n\t// Code Blocks\n\t'--char-code-bg',\n\t'--char-code-text',\n\t'--char-code-header-bg',\n\n\t// Sizing\n\t'--char-radius',\n\t'--char-radius-sm',\n\t'--char-radius-md',\n\t'--char-radius-lg',\n\t'--char-radius-xl',\n\t'--char-radius-2xl',\n\t'--char-radius-3xl',\n\t'--char-radius-full',\n\t'--char-spacing-unit',\n\n\t// Typography\n\t'--char-font-sans',\n\t'--char-font-mono',\n\t'--char-font-size-xs',\n\t'--char-font-size-sm',\n\t'--char-font-size-base',\n\t'--char-font-size-lg',\n\n\t// Motion\n\t'--char-duration-fast',\n\t'--char-duration-normal',\n\t'--char-duration-slow',\n\t'--char-easing-default',\n\t'--char-easing-spring',\n\n\t// Z-index\n\t'--char-z-base',\n\t'--char-z-content',\n\t'--char-z-overlay',\n\t'--char-z-max',\n\n\t// Shadows\n\t'--char-shadow-sm',\n\t'--char-shadow-md',\n\t'--char-shadow-lg',\n\n\t// Blur\n\t'--char-blur-sm',\n\t'--char-blur-md',\n\t'--char-blur-lg',\n] as const\n\nconst MCP_UI_STYLE_VARIABLE_NAMES = [\n\t// Background colors\n\t'--color-background-primary',\n\t'--color-background-secondary',\n\t'--color-background-tertiary',\n\t'--color-background-inverse',\n\t'--color-background-ghost',\n\t'--color-background-info',\n\t'--color-background-danger',\n\t'--color-background-success',\n\t'--color-background-warning',\n\t'--color-background-disabled',\n\n\t// Text colors\n\t'--color-text-primary',\n\t'--color-text-secondary',\n\t'--color-text-tertiary',\n\t'--color-text-inverse',\n\t'--color-text-ghost',\n\t'--color-text-info',\n\t'--color-text-danger',\n\t'--color-text-success',\n\t'--color-text-warning',\n\t'--color-text-disabled',\n\n\t// Border colors\n\t'--color-border-primary',\n\t'--color-border-secondary',\n\t'--color-border-tertiary',\n\t'--color-border-inverse',\n\t'--color-border-ghost',\n\t'--color-border-info',\n\t'--color-border-danger',\n\t'--color-border-success',\n\t'--color-border-warning',\n\t'--color-border-disabled',\n\n\t// Ring colors\n\t'--color-ring-primary',\n\t'--color-ring-secondary',\n\t'--color-ring-inverse',\n\t'--color-ring-info',\n\t'--color-ring-danger',\n\t'--color-ring-success',\n\t'--color-ring-warning',\n\n\t// Typography - Family\n\t'--font-sans',\n\t'--font-mono',\n\n\t// Typography - Weight\n\t'--font-weight-normal',\n\t'--font-weight-medium',\n\t'--font-weight-semibold',\n\t'--font-weight-bold',\n\n\t// Typography - Text Size\n\t'--font-text-xs-size',\n\t'--font-text-sm-size',\n\t'--font-text-md-size',\n\t'--font-text-lg-size',\n\n\t// Typography - Heading Size\n\t'--font-heading-xs-size',\n\t'--font-heading-sm-size',\n\t'--font-heading-md-size',\n\t'--font-heading-lg-size',\n\t'--font-heading-xl-size',\n\t'--font-heading-2xl-size',\n\t'--font-heading-3xl-size',\n\n\t// Typography - Text Line Height\n\t'--font-text-xs-line-height',\n\t'--font-text-sm-line-height',\n\t'--font-text-md-line-height',\n\t'--font-text-lg-line-height',\n\n\t// Typography - Heading Line Height\n\t'--font-heading-xs-line-height',\n\t'--font-heading-sm-line-height',\n\t'--font-heading-md-line-height',\n\t'--font-heading-lg-line-height',\n\t'--font-heading-xl-line-height',\n\t'--font-heading-2xl-line-height',\n\t'--font-heading-3xl-line-height',\n\n\t// Border radius\n\t'--border-radius-xs',\n\t'--border-radius-sm',\n\t'--border-radius-md',\n\t'--border-radius-lg',\n\t'--border-radius-xl',\n\t'--border-radius-full',\n\n\t// Border width\n\t'--border-width-regular',\n\n\t// Shadows\n\t'--shadow-hairline',\n\t'--shadow-sm',\n\t'--shadow-md',\n\t'--shadow-lg',\n] as const\n\nexport const CHAR_CSS_VARIABLE_NAMES = [\n\t...CHAR_PUBLIC_VARIABLE_NAMES,\n\t...MCP_UI_STYLE_VARIABLE_NAMES,\n] as const\n","/**\n * Host Context Merge Utilities\n *\n * Canonical merge logic for CharHostContext deltas. Used by both the host-side\n * web component and the iframe-side useHostContext hook to ensure identical\n * merge behavior on both sides of the postMessage bridge.\n */\n\nimport type { CharHostContext } from '../types'\n\nexport function mergeStyles(\n\tcurrent: CharHostContext['styles'] | undefined,\n\tpatch: CharHostContext['styles'] | undefined,\n): CharHostContext['styles'] | undefined {\n\tif (!patch) return current\n\treturn {\n\t\t...current,\n\t\t...patch,\n\t\t// variables are sent as a snapshot so removals propagate\n\t\tvariables: patch.variables ?? current?.variables,\n\t\tfonts: patch.fonts ?? current?.fonts,\n\t}\n}\n\nexport function shallowMerge<T extends object>(\n\tcurrent: T | undefined,\n\tpatch: T | undefined,\n): T | undefined {\n\tif (!patch) return current\n\treturn { ...current, ...patch }\n}\n\nexport function mergeHostContext(\n\tcurrent: CharHostContext | null,\n\tpatch: CharHostContext,\n): CharHostContext {\n\tconst previous = current ?? {}\n\treturn {\n\t\t...previous,\n\t\t...patch,\n\t\tstyles: mergeStyles(previous.styles, patch.styles),\n\t\tcontainerDimensions: shallowMerge(previous.containerDimensions, patch.containerDimensions),\n\t\tdeviceCapabilities: shallowMerge(previous.deviceCapabilities, patch.deviceCapabilities),\n\t\tsafeAreaInsets: shallowMerge(previous.safeAreaInsets, patch.safeAreaInsets),\n\t\thostCapabilities: shallowMerge(previous.hostCapabilities, patch.hostCapabilities),\n\t}\n}\n"],"mappings":";;;;;;;;;;;AAUA,MAAa,4BAA4B;AAEzC,SAAgB,kBAAkB,OAAe,gBAAgC;CAChF,IAAI,QAAQ;AACZ,MAAK,IAAI,IAAI,iBAAiB,GAAG,IAAI,MAAM,QAAQ,KAAK;EACvD,MAAM,OAAO,MAAM;AACnB,MAAI,SAAS,IAAK,UAAS;WAClB,SAAS,IAAK,UAAS;AAChC,MAAI,UAAU,EAAG,QAAO;;AAEzB,QAAO;;AAGR,SAAgB,mBAAmB,OAA6C;CAC/E,IAAI,QAAQ;AACZ,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACtC,MAAM,OAAO,MAAM;AACnB,MAAI,SAAS,IAAK,UAAS;WAClB,SAAS,IAAK,SAAQ,KAAK,IAAI,GAAG,QAAQ,EAAE;WAC5C,SAAS,OAAO,UAAU,EAAG,QAAO,CAAC,MAAM,MAAM,GAAG,EAAE,EAAE,MAAM,MAAM,IAAI,EAAE,CAAC;;AAErF,QAAO,CAAC,OAAO,OAAU;;AAG1B,SAAgB,gBACf,UACA,UACA,MACA,OACqB;AACrB,KAAI,CAAC,SAAU,QAAO;AACtB,QAAO,gBAAgB,UAAU,UAAU,MAAM,QAAQ,EAAE,IAAI;;AAGhE,SAAgB,mBACf,cACA,UACA,UACA,MACA,OACqB;AACrB,KAAI,QAAQ,2BAA2B;AACtC,UAAQ,KAAK,sDAAsD,aAAa,iCAAiC;AACjH,SAAO,UAAU,MAAM;;AAGxB,KAAI,CAAC,aAAa,WAAW,KAAK,IAAI,KAAK,IAAI,aAAa,CAC3D,QAAO,gBAAgB,UAAU,UAAU,MAAM,MAAM;CAGxD,MAAM,WAAW,IAAI,IAAI,KAAK;AAC9B,UAAS,IAAI,aAAa;CAE1B,MAAM,WAAW,SAAS,iBAAiB,aAAa,CAAC,MAAM;AAC/D,KAAI,UAAU;EACb,MAAM,cAAc,gBAAgB,UAAU,UAAU,UAAU,QAAQ,EAAE;AAC5E,MAAI,YAAa,QAAO;;AAGzB,QAAO,gBAAgB,UAAU,UAAU,MAAM,MAAM;;AAGxD,SAAgB,gBACf,OACA,UACA,MACA,QAAQ,GACC;CACT,MAAM,UAAU,MAAM,MAAM;AAC5B,KAAI,CAAC,WAAW,CAAC,QAAQ,SAAS,OAAO,IAAI,QAAQ,0BACpD,QAAO;CAGR,IAAI,SAAS;CACb,IAAI,WAAW;CACf,IAAI,cAAc;AAElB,QAAO,SAAS,QAAQ,QAAQ;EAC/B,MAAM,WAAW,QAAQ,QAAQ,QAAQ,OAAO;AAChD,MAAI,aAAa,IAAI;AACpB,eAAY,QAAQ,MAAM,OAAO;AACjC;;AAGD,cAAY,QAAQ,MAAM,QAAQ,SAAS;EAE3C,MAAM,iBAAiB,WAAW;EAClC,MAAM,kBAAkB,kBAAkB,SAAS,eAAe;AAClE,MAAI,oBAAoB,IAAI;AAC3B,eAAY,QAAQ,MAAM,SAAS;AACnC;;EAID,MAAM,CAAC,iBAAiB,eAAe,mBADvB,QAAQ,MAAM,iBAAiB,GAAG,gBAAgB,CACA;EAClE,MAAM,eAAe,gBAAgB,MAAM;EAC3C,MAAM,WAAW,aAAa,MAAM;EAEpC,MAAM,cAAc,eACjB,mBAAmB,cAAc,UAAU,UAAU,MAAM,QAAQ,EAAE,GACrE;AAEH,MAAI,gBAAgB,QAAW;AAC9B,eAAY;AACZ,iBAAc;QAEd,aAAY,QAAQ,MAAM,UAAU,kBAAkB,EAAE;AAGzD,WAAS,kBAAkB;;CAG5B,MAAM,aAAa,SAAS,MAAM;AAClC,KAAI,CAAC,eAAe,CAAC,WAAW,SAAS,OAAO,CAC/C,QAAO;AAGR,QAAO,gBAAgB,YAAY,UAAU,MAAM,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;ACjH9D,MAAa,gCAAgC;AAC7C,MAAa,2BAA2B;AAExC,MAAM,uBAAuB;AAC7B,MAAM,qBAAqB;AAC3B,MAAM,sBAAsB;AAC5B,MAAM,oCAAoC;;;;;AAM1C,SAAS,yBAAyB,OAAuB;AAExD,QADwB,MAAM,QAAQ,qBAAqB,GAAG,CACvC,aAAa,CAAC,QAAQ,8BAA8B,GAAG;;;;;;;;;AAU/E,SAAS,iCAAiC,OAAuB;AAChE,QAAO,MAAM,QAAQ,mCAAmC,IAAI;;;;;;;;;AAU7D,SAAgB,yBAAyB,OAAe,cAA2C;CAClG,MAAM,UAAU,iCAAiC,MAAM,CAAC,MAAM;AAC9D,KAAI,CAAC,QAAS,QAAO;AACrB,KAAI,QAAQ,SAAS,+BAA+B;AACnD,UAAQ,KAAK,uBAAuB,gBAAgB,YAAY,uCAAuC,QAAQ,OAAO,KAAK,8BAA8B,GAAG;AAC5J;;AAED,KAAI,qBAAqB,KAAK,QAAQ,EAAE;AACvC,UAAQ,KAAK,uBAAuB,gBAAgB,YAAY,wCAAwC;AACxG;;CAID,MAAM,eAAe,2BADF,yBAAyB,QAAQ,CACO;AAC3D,KAAI,aAAc,QAAO,cAAc,cAAc,aAAa;AAElE,QAAO;;;;;;AAOR,SAAgB,oBAAoB,SAAqC;CACxE,MAAM,UAAU,QAAQ,MAAM;AAC9B,KAAI,CAAC,QAAS,QAAO;AACrB,KAAI,QAAQ,SAAS,0BAA0B;AAC9C,UAAQ,KAAK,4DAA4D,QAAQ,OAAO,KAAK,yBAAyB,GAAG;AACzH;;AAED,KAAI,qBAAqB,KAAK,QAAQ,EAAE;AACvC,UAAQ,KAAK,6DAA6D;AAC1E;;CAID,MAAM,eAAe,oBADF,yBAAyB,QAAQ,CACA;AACpD,KAAI,cAAc;AACjB,UAAQ,KAAK,0DAA0D,aAAa,GAAG;AACvF;;CAGD,MAAM,kBAAkB,QAAQ,QAAQ,qBAAqB,GAAG,CAAC,MAAM;AACvE,KAAI,CAAC,mBAAmB,KAAK,gBAAgB,EAAE;AAC9C,UAAQ,KAAK,mEAAmE;AAChF;;AAGD,QAAO;;AAGR,SAAS,2BAA2B,iBAA6C;AAChF,KAAI,gBAAgB,SAAS,cAAc,CAAE,QAAO;AACpD,KAAI,gBAAgB,SAAS,YAAY,CAAE,QAAO;AAClD,KAAI,gBAAgB,SAAS,cAAc,CAAE,QAAO;AACpD,KAAI,gBAAgB,SAAS,UAAU,CAAE,QAAO;AAChD,KAAI,gBAAgB,SAAS,eAAe,CAAE,QAAO;AACrD,KAAI,gBAAgB,SAAS,OAAO,CAAE,QAAO;;AAI9C,SAAS,oBAAoB,iBAA6C;AACzE,KAAI,gBAAgB,SAAS,cAAc,CAAE,QAAO;AACpD,KAAI,gBAAgB,SAAS,YAAY,CAAE,QAAO;AAClD,KAAI,gBAAgB,SAAS,cAAc,CAAE,QAAO;AACpD,KAAI,gBAAgB,SAAS,eAAe,CAAE,QAAO;;AAItD,SAAS,cAAc,cAAkC,cAAiC;AACzF,SAAQ,KAAK,uBAAuB,gBAAgB,YAAY,qCAAqC,aAAa,GAAG;;;;;;;;;;;;;;;;AC3GtH,MAAM,6BAA6B;CAElC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CAGA;CACA;CAGA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CAGA;CACA;CACA;CAGA;CACA;CACA;CACA;AAED,MAAM,8BAA8B;CAEnC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CAGA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CAGA;CAGA;CACA;CACA;CACA;CACA;AAED,MAAa,0BAA0B,CACtC,GAAG,4BACH,GAAG,4BACH;;;;AClND,SAAgB,YACf,SACA,OACwC;AACxC,KAAI,CAAC,MAAO,QAAO;AACnB,QAAO;EACN,GAAG;EACH,GAAG;EAEH,WAAW,MAAM,aAAa,SAAS;EACvC,OAAO,MAAM,SAAS,SAAS;EAC/B;;AAGF,SAAgB,aACf,SACA,OACgB;AAChB,KAAI,CAAC,MAAO,QAAO;AACnB,QAAO;EAAE,GAAG;EAAS,GAAG;EAAO;;AAGhC,SAAgB,iBACf,SACA,OACkB;CAClB,MAAM,WAAW,WAAW,EAAE;AAC9B,QAAO;EACN,GAAG;EACH,GAAG;EACH,QAAQ,YAAY,SAAS,QAAQ,MAAM,OAAO;EAClD,qBAAqB,aAAa,SAAS,qBAAqB,MAAM,oBAAoB;EAC1F,oBAAoB,aAAa,SAAS,oBAAoB,MAAM,mBAAmB;EACvF,gBAAgB,aAAa,SAAS,gBAAgB,MAAM,eAAe;EAC3E,kBAAkB,aAAa,SAAS,kBAAkB,MAAM,iBAAiB;EACjF"}
|