dsh-codex-subscription 2.2.11 → 2.4.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/README.en.md +41 -43
- package/README.md +49 -38
- package/lib/client.js +905 -32
- package/lib/index.js +58 -18
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -2321,6 +2321,796 @@ window.__ModuleLoader__.load({
|
|
|
2321
2321
|
}))
|
|
2322
2322
|
};
|
|
2323
2323
|
}
|
|
2324
|
+
//#endregion
|
|
2325
|
+
//#region src/sketch-svg.js
|
|
2326
|
+
const MAX_SVG_CHARACTERS = 2e5;
|
|
2327
|
+
const MAX_BEZIER_SEGMENTS = 64;
|
|
2328
|
+
const FLATTEN_STEPS = 10;
|
|
2329
|
+
const NAMED_COLORS = {
|
|
2330
|
+
black: "#000000",
|
|
2331
|
+
white: "#ffffff",
|
|
2332
|
+
red: "#ff0000",
|
|
2333
|
+
green: "#008000",
|
|
2334
|
+
blue: "#0000ff",
|
|
2335
|
+
yellow: "#ffff00",
|
|
2336
|
+
orange: "#ffa500",
|
|
2337
|
+
purple: "#800080",
|
|
2338
|
+
pink: "#ffc0cb",
|
|
2339
|
+
brown: "#a52a2a",
|
|
2340
|
+
gray: "#808080",
|
|
2341
|
+
grey: "#808080",
|
|
2342
|
+
silver: "#c0c0c0",
|
|
2343
|
+
gold: "#ffd700",
|
|
2344
|
+
navy: "#000080",
|
|
2345
|
+
teal: "#008080",
|
|
2346
|
+
maroon: "#800000",
|
|
2347
|
+
olive: "#808000",
|
|
2348
|
+
lime: "#00ff00",
|
|
2349
|
+
aqua: "#00ffff",
|
|
2350
|
+
cyan: "#00ffff",
|
|
2351
|
+
magenta: "#ff00ff",
|
|
2352
|
+
fuchsia: "#ff00ff",
|
|
2353
|
+
ivory: "#fffff0",
|
|
2354
|
+
beige: "#f5f5dc",
|
|
2355
|
+
tan: "#d2b48c",
|
|
2356
|
+
khaki: "#f0e68c",
|
|
2357
|
+
coral: "#ff7f50",
|
|
2358
|
+
salmon: "#fa8072",
|
|
2359
|
+
crimson: "#dc143c",
|
|
2360
|
+
indigo: "#4b0082",
|
|
2361
|
+
violet: "#ee82ee",
|
|
2362
|
+
turquoise: "#40e0d0",
|
|
2363
|
+
skyblue: "#87ceeb",
|
|
2364
|
+
darkgray: "#a9a9a9",
|
|
2365
|
+
darkgrey: "#a9a9a9",
|
|
2366
|
+
lightgray: "#d3d3d3",
|
|
2367
|
+
lightgrey: "#d3d3d3",
|
|
2368
|
+
darkred: "#8b0000",
|
|
2369
|
+
darkgreen: "#006400",
|
|
2370
|
+
darkblue: "#00008b",
|
|
2371
|
+
transparent: "none"
|
|
2372
|
+
};
|
|
2373
|
+
const UNSUPPORTED = /* @__PURE__ */ new Set([
|
|
2374
|
+
"text",
|
|
2375
|
+
"tspan",
|
|
2376
|
+
"image",
|
|
2377
|
+
"foreignObject",
|
|
2378
|
+
"filter",
|
|
2379
|
+
"clipPath",
|
|
2380
|
+
"mask",
|
|
2381
|
+
"pattern",
|
|
2382
|
+
"style",
|
|
2383
|
+
"script",
|
|
2384
|
+
"switch",
|
|
2385
|
+
"marker",
|
|
2386
|
+
"symbol"
|
|
2387
|
+
]);
|
|
2388
|
+
const IGNORED = /* @__PURE__ */ new Set([
|
|
2389
|
+
"title",
|
|
2390
|
+
"desc",
|
|
2391
|
+
"metadata",
|
|
2392
|
+
"defs",
|
|
2393
|
+
"linearGradient",
|
|
2394
|
+
"radialGradient",
|
|
2395
|
+
"stop",
|
|
2396
|
+
"namedview",
|
|
2397
|
+
"sodipodi:namedview"
|
|
2398
|
+
]);
|
|
2399
|
+
const decode = (value) => value.split(""").join("\"").split("'").join("'").split("<").join("<").split(">").join(">").split("&").join("&");
|
|
2400
|
+
function parseXml(text) {
|
|
2401
|
+
const tag = /<!--[\s\S]*?-->|<\?[\s\S]*?\?>|<!\[CDATA\[[\s\S]*?\]\]>|<!DOCTYPE[^>]*>|<(\/?)([A-Za-z_][\w:.-]*)((?:\s+[^\s=/>]+\s*=\s*(?:"[^"]*"|'[^']*'))*)\s*(\/?)>/g;
|
|
2402
|
+
const attribute = /([^\s=/>]+)\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
|
|
2403
|
+
const root = {
|
|
2404
|
+
name: "#root",
|
|
2405
|
+
attrs: {},
|
|
2406
|
+
children: []
|
|
2407
|
+
};
|
|
2408
|
+
const stack = [root];
|
|
2409
|
+
for (let match = tag.exec(text); match; match = tag.exec(text)) {
|
|
2410
|
+
if (match[2] === void 0) continue;
|
|
2411
|
+
if (match[1] === "/") {
|
|
2412
|
+
if (stack.length > 1 && stack.at(-1).name === match[2]) stack.pop();
|
|
2413
|
+
else throw Error(`SVG is malformed: unexpected </${match[2]}>`);
|
|
2414
|
+
continue;
|
|
2415
|
+
}
|
|
2416
|
+
const attrs = {};
|
|
2417
|
+
for (let item = attribute.exec(match[3]); item; item = attribute.exec(match[3])) attrs[item[1]] = decode(item[2] ?? item[3]);
|
|
2418
|
+
const node = {
|
|
2419
|
+
name: match[2],
|
|
2420
|
+
attrs,
|
|
2421
|
+
children: []
|
|
2422
|
+
};
|
|
2423
|
+
stack.at(-1).children.push(node);
|
|
2424
|
+
if (match[4] !== "/") stack.push(node);
|
|
2425
|
+
}
|
|
2426
|
+
if (stack.length !== 1) throw Error(`SVG is malformed: <${stack.at(-1).name}> is not closed`);
|
|
2427
|
+
return root;
|
|
2428
|
+
}
|
|
2429
|
+
const IDENTITY = [
|
|
2430
|
+
1,
|
|
2431
|
+
0,
|
|
2432
|
+
0,
|
|
2433
|
+
1,
|
|
2434
|
+
0,
|
|
2435
|
+
0
|
|
2436
|
+
];
|
|
2437
|
+
const multiply = (m, n) => [
|
|
2438
|
+
m[0] * n[0] + m[2] * n[1],
|
|
2439
|
+
m[1] * n[0] + m[3] * n[1],
|
|
2440
|
+
m[0] * n[2] + m[2] * n[3],
|
|
2441
|
+
m[1] * n[2] + m[3] * n[3],
|
|
2442
|
+
m[0] * n[4] + m[2] * n[5] + m[4],
|
|
2443
|
+
m[1] * n[4] + m[3] * n[5] + m[5]
|
|
2444
|
+
];
|
|
2445
|
+
const apply$1 = (m, x, y) => [m[0] * x + m[2] * y + m[4], m[1] * x + m[3] * y + m[5]];
|
|
2446
|
+
const NUMBER = /[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?/g;
|
|
2447
|
+
const numbers = (text) => (String(text ?? "").match(NUMBER) ?? []).map(Number);
|
|
2448
|
+
function parseTransform(text) {
|
|
2449
|
+
let matrix = IDENTITY;
|
|
2450
|
+
const source = String(text ?? "");
|
|
2451
|
+
const item = /(matrix|translate|scale|rotate|skewX|skewY)\s*\(([^)]*)\)/g;
|
|
2452
|
+
if (source.replace(item, "").replace(/[\s,]/g, "")) throw Error(`Unsupported SVG transform: ${source}`);
|
|
2453
|
+
for (let match = item.exec(source); match; match = item.exec(source)) {
|
|
2454
|
+
const v = numbers(match[2]);
|
|
2455
|
+
let next;
|
|
2456
|
+
if (match[1] === "matrix" && v.length === 6) next = v;
|
|
2457
|
+
else if (match[1] === "translate" && v.length >= 1) next = [
|
|
2458
|
+
1,
|
|
2459
|
+
0,
|
|
2460
|
+
0,
|
|
2461
|
+
1,
|
|
2462
|
+
v[0],
|
|
2463
|
+
v[1] ?? 0
|
|
2464
|
+
];
|
|
2465
|
+
else if (match[1] === "scale" && v.length >= 1) next = [
|
|
2466
|
+
v[0],
|
|
2467
|
+
0,
|
|
2468
|
+
0,
|
|
2469
|
+
v[1] ?? v[0],
|
|
2470
|
+
0,
|
|
2471
|
+
0
|
|
2472
|
+
];
|
|
2473
|
+
else if (match[1] === "rotate" && v.length >= 1) {
|
|
2474
|
+
const a = v[0] * Math.PI / 180, c = Math.cos(a), s = Math.sin(a);
|
|
2475
|
+
const turn = [
|
|
2476
|
+
c,
|
|
2477
|
+
s,
|
|
2478
|
+
-s,
|
|
2479
|
+
c,
|
|
2480
|
+
0,
|
|
2481
|
+
0
|
|
2482
|
+
];
|
|
2483
|
+
next = v.length >= 3 ? multiply(multiply([
|
|
2484
|
+
1,
|
|
2485
|
+
0,
|
|
2486
|
+
0,
|
|
2487
|
+
1,
|
|
2488
|
+
v[1],
|
|
2489
|
+
v[2]
|
|
2490
|
+
], turn), [
|
|
2491
|
+
1,
|
|
2492
|
+
0,
|
|
2493
|
+
0,
|
|
2494
|
+
1,
|
|
2495
|
+
-v[1],
|
|
2496
|
+
-v[2]
|
|
2497
|
+
]) : turn;
|
|
2498
|
+
} else if (match[1] === "skewX" && v.length === 1) next = [
|
|
2499
|
+
1,
|
|
2500
|
+
0,
|
|
2501
|
+
Math.tan(v[0] * Math.PI / 180),
|
|
2502
|
+
1,
|
|
2503
|
+
0,
|
|
2504
|
+
0
|
|
2505
|
+
];
|
|
2506
|
+
else if (match[1] === "skewY" && v.length === 1) next = [
|
|
2507
|
+
1,
|
|
2508
|
+
Math.tan(v[0] * Math.PI / 180),
|
|
2509
|
+
0,
|
|
2510
|
+
1,
|
|
2511
|
+
0,
|
|
2512
|
+
0
|
|
2513
|
+
];
|
|
2514
|
+
else throw Error(`Unsupported SVG transform: ${match[0]}`);
|
|
2515
|
+
matrix = multiply(matrix, next);
|
|
2516
|
+
}
|
|
2517
|
+
return matrix;
|
|
2518
|
+
}
|
|
2519
|
+
function parseColor(value) {
|
|
2520
|
+
const text = String(value ?? "").trim().toLowerCase();
|
|
2521
|
+
if (!text || text === "none") return "none";
|
|
2522
|
+
if (text === "currentcolor") return "#000000";
|
|
2523
|
+
if (Object.hasOwn(NAMED_COLORS, text)) return NAMED_COLORS[text];
|
|
2524
|
+
const hex = /^#([0-9a-f]{3}|[0-9a-f]{6})$/.exec(text);
|
|
2525
|
+
if (hex) return hex[1].length === 3 ? `#${[...hex[1]].map((ch) => ch + ch).join("")}` : text;
|
|
2526
|
+
const rgb = /^rgba?\(([^)]*)\)$/.exec(text);
|
|
2527
|
+
if (rgb) {
|
|
2528
|
+
const parts = rgb[1].split(/[\s,/]+/).filter(Boolean);
|
|
2529
|
+
const channel = (part) => Math.max(0, Math.min(255, Math.round(part.endsWith("%") ? parseFloat(part) * 2.55 : parseFloat(part))));
|
|
2530
|
+
if (parts.length >= 3) return `#${parts.slice(0, 3).map((part) => channel(part).toString(16).padStart(2, "0")).join("")}`;
|
|
2531
|
+
}
|
|
2532
|
+
throw Error(`Unsupported SVG color: ${value}. Use #rrggbb, #rgb, rgb(), a basic color name, none, or a gradient id.`);
|
|
2533
|
+
}
|
|
2534
|
+
function styleOf(node, parent) {
|
|
2535
|
+
const own = { ...node.attrs };
|
|
2536
|
+
if (own.style) for (const rule of own.style.split(";")) {
|
|
2537
|
+
const at = rule.indexOf(":");
|
|
2538
|
+
if (at > 0) own[rule.slice(0, at).trim()] = rule.slice(at + 1).trim();
|
|
2539
|
+
}
|
|
2540
|
+
const pick = (name, fallback) => own[name] === void 0 || own[name] === "inherit" ? fallback : own[name];
|
|
2541
|
+
const number = (name, fallback) => {
|
|
2542
|
+
const value = pick(name, void 0);
|
|
2543
|
+
return value === void 0 ? fallback : Number.parseFloat(value);
|
|
2544
|
+
};
|
|
2545
|
+
return {
|
|
2546
|
+
fill: pick("fill", parent.fill),
|
|
2547
|
+
stroke: pick("stroke", parent.stroke),
|
|
2548
|
+
strokeWidth: number("stroke-width", parent.strokeWidth),
|
|
2549
|
+
fillOpacity: number("fill-opacity", parent.fillOpacity),
|
|
2550
|
+
strokeOpacity: number("stroke-opacity", parent.strokeOpacity),
|
|
2551
|
+
opacity: parent.opacity * number("opacity", 1),
|
|
2552
|
+
display: own.display === "none" || own.visibility === "hidden" ? "none" : "inline"
|
|
2553
|
+
};
|
|
2554
|
+
}
|
|
2555
|
+
function arcToCubics(x1, y1, rx, ry, rotation, large, sweep, x2, y2) {
|
|
2556
|
+
if (x1 === x2 && y1 === y2) return [];
|
|
2557
|
+
rx = Math.abs(rx);
|
|
2558
|
+
ry = Math.abs(ry);
|
|
2559
|
+
if (!rx || !ry) return [[
|
|
2560
|
+
x1,
|
|
2561
|
+
y1,
|
|
2562
|
+
x2,
|
|
2563
|
+
y2,
|
|
2564
|
+
x2,
|
|
2565
|
+
y2
|
|
2566
|
+
]];
|
|
2567
|
+
const phi = rotation * Math.PI / 180, cos = Math.cos(phi), sin = Math.sin(phi);
|
|
2568
|
+
const dx = (x1 - x2) / 2, dy = (y1 - y2) / 2;
|
|
2569
|
+
const x1p = cos * dx + sin * dy, y1p = -sin * dx + cos * dy;
|
|
2570
|
+
const lambda = x1p * x1p / (rx * rx) + y1p * y1p / (ry * ry);
|
|
2571
|
+
if (lambda > 1) {
|
|
2572
|
+
rx *= Math.sqrt(lambda);
|
|
2573
|
+
ry *= Math.sqrt(lambda);
|
|
2574
|
+
}
|
|
2575
|
+
const sign = large === sweep ? -1 : 1;
|
|
2576
|
+
const numerator = rx * rx * ry * ry - rx * rx * y1p * y1p - ry * ry * x1p * x1p;
|
|
2577
|
+
const denominator = rx * rx * y1p * y1p + ry * ry * x1p * x1p;
|
|
2578
|
+
const factor = sign * Math.sqrt(Math.max(0, numerator / denominator));
|
|
2579
|
+
const cxp = factor * rx * y1p / ry, cyp = -factor * ry * x1p / rx;
|
|
2580
|
+
const cx = cos * cxp - sin * cyp + (x1 + x2) / 2, cy = sin * cxp + cos * cyp + (y1 + y2) / 2;
|
|
2581
|
+
const angle = (ux, uy, vx, vy) => Math.atan2(ux * vy - uy * vx, ux * vx + uy * vy);
|
|
2582
|
+
const theta = angle(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry);
|
|
2583
|
+
let delta = angle((x1p - cxp) / rx, (y1p - cyp) / ry, (-x1p - cxp) / rx, (-y1p - cyp) / ry);
|
|
2584
|
+
if (!sweep && delta > 0) delta -= 2 * Math.PI;
|
|
2585
|
+
if (sweep && delta < 0) delta += 2 * Math.PI;
|
|
2586
|
+
const count = Math.max(1, Math.ceil(Math.abs(delta) / (Math.PI / 2) - 1e-9));
|
|
2587
|
+
const step = delta / count, k = 4 / 3 * Math.tan(step / 4);
|
|
2588
|
+
const out = [];
|
|
2589
|
+
for (let index = 0; index < count; index++) {
|
|
2590
|
+
const a1 = theta + index * step, a2 = a1 + step;
|
|
2591
|
+
const point = (a, scale) => {
|
|
2592
|
+
const px = rx * Math.cos(a), py = ry * Math.sin(a);
|
|
2593
|
+
const tx = -rx * Math.sin(a) * scale, ty = ry * Math.cos(a) * scale;
|
|
2594
|
+
return [
|
|
2595
|
+
cos * px - sin * py + cx,
|
|
2596
|
+
sin * px + cos * py + cy,
|
|
2597
|
+
cos * tx - sin * ty,
|
|
2598
|
+
sin * tx + cos * ty
|
|
2599
|
+
];
|
|
2600
|
+
};
|
|
2601
|
+
const p1 = point(a1, k), p2 = point(a2, k);
|
|
2602
|
+
out.push([
|
|
2603
|
+
p1[0] + p1[2],
|
|
2604
|
+
p1[1] + p1[3],
|
|
2605
|
+
p2[0] - p2[2],
|
|
2606
|
+
p2[1] - p2[3],
|
|
2607
|
+
p2[0],
|
|
2608
|
+
p2[1]
|
|
2609
|
+
]);
|
|
2610
|
+
}
|
|
2611
|
+
return out;
|
|
2612
|
+
}
|
|
2613
|
+
function parsePathData(data) {
|
|
2614
|
+
const source = String(data ?? "");
|
|
2615
|
+
const subpaths = [];
|
|
2616
|
+
let index = 0, command = "", current, x = 0, y = 0, startX = 0, startY = 0, lastControl, lastCommand = "";
|
|
2617
|
+
const skip = () => {
|
|
2618
|
+
while (index < source.length && /[\s,]/.test(source[index])) index++;
|
|
2619
|
+
};
|
|
2620
|
+
const readNumber = () => {
|
|
2621
|
+
skip();
|
|
2622
|
+
NUMBER.lastIndex = index;
|
|
2623
|
+
const match = NUMBER.exec(source);
|
|
2624
|
+
if (!match || match.index !== index) throw Error(`Malformed SVG path data near "${source.slice(index, index + 12)}"`);
|
|
2625
|
+
index = NUMBER.lastIndex;
|
|
2626
|
+
return Number(match[0]);
|
|
2627
|
+
};
|
|
2628
|
+
const readFlag = () => {
|
|
2629
|
+
skip();
|
|
2630
|
+
const ch = source[index];
|
|
2631
|
+
if (ch !== "0" && ch !== "1") throw Error("Malformed SVG arc flag in path data");
|
|
2632
|
+
index++;
|
|
2633
|
+
return ch === "1";
|
|
2634
|
+
};
|
|
2635
|
+
const begin = (px, py) => {
|
|
2636
|
+
current = {
|
|
2637
|
+
start: [px, py],
|
|
2638
|
+
curves: [],
|
|
2639
|
+
closed: false,
|
|
2640
|
+
straight: true
|
|
2641
|
+
};
|
|
2642
|
+
subpaths.push(current);
|
|
2643
|
+
};
|
|
2644
|
+
const line = (px, py) => {
|
|
2645
|
+
current.curves.push([
|
|
2646
|
+
x,
|
|
2647
|
+
y,
|
|
2648
|
+
px,
|
|
2649
|
+
py,
|
|
2650
|
+
px,
|
|
2651
|
+
py
|
|
2652
|
+
]);
|
|
2653
|
+
x = px;
|
|
2654
|
+
y = py;
|
|
2655
|
+
};
|
|
2656
|
+
const cubic = (c1x, c1y, c2x, c2y, px, py) => {
|
|
2657
|
+
current.curves.push([
|
|
2658
|
+
c1x,
|
|
2659
|
+
c1y,
|
|
2660
|
+
c2x,
|
|
2661
|
+
c2y,
|
|
2662
|
+
px,
|
|
2663
|
+
py
|
|
2664
|
+
]);
|
|
2665
|
+
current.straight = false;
|
|
2666
|
+
lastControl = [c2x, c2y];
|
|
2667
|
+
x = px;
|
|
2668
|
+
y = py;
|
|
2669
|
+
};
|
|
2670
|
+
for (;;) {
|
|
2671
|
+
skip();
|
|
2672
|
+
if (index >= source.length) break;
|
|
2673
|
+
if (/[MmLlHhVvCcSsQqTtAaZz]/.test(source[index])) command = source[index++];
|
|
2674
|
+
else if (!command) throw Error("SVG path data must start with a command");
|
|
2675
|
+
else if (command === "M") command = "L";
|
|
2676
|
+
else if (command === "m") command = "l";
|
|
2677
|
+
else if (command === "Z" || command === "z") throw Error("Unexpected number after Z in SVG path data");
|
|
2678
|
+
const relative = command === command.toLowerCase();
|
|
2679
|
+
const upper = command.toUpperCase();
|
|
2680
|
+
const ox = relative ? x : 0, oy = relative ? y : 0;
|
|
2681
|
+
if (upper === "M") {
|
|
2682
|
+
const px = readNumber() + ox, py = readNumber() + oy;
|
|
2683
|
+
x = startX = px;
|
|
2684
|
+
y = startY = py;
|
|
2685
|
+
begin(px, py);
|
|
2686
|
+
lastControl = void 0;
|
|
2687
|
+
} else if (upper === "Z") {
|
|
2688
|
+
if (current && !current.closed) {
|
|
2689
|
+
if (x !== startX || y !== startY) line(startX, startY);
|
|
2690
|
+
current.closed = true;
|
|
2691
|
+
}
|
|
2692
|
+
x = startX;
|
|
2693
|
+
y = startY;
|
|
2694
|
+
lastControl = void 0;
|
|
2695
|
+
current = void 0;
|
|
2696
|
+
} else {
|
|
2697
|
+
if (!current) {
|
|
2698
|
+
begin(x, y);
|
|
2699
|
+
startX = x;
|
|
2700
|
+
startY = y;
|
|
2701
|
+
}
|
|
2702
|
+
if (upper === "L") line(readNumber() + ox, readNumber() + oy);
|
|
2703
|
+
else if (upper === "H") line(readNumber() + ox, y);
|
|
2704
|
+
else if (upper === "V") line(x, readNumber() + oy);
|
|
2705
|
+
else if (upper === "C") cubic(readNumber() + ox, readNumber() + oy, readNumber() + ox, readNumber() + oy, readNumber() + ox, readNumber() + oy);
|
|
2706
|
+
else if (upper === "S") {
|
|
2707
|
+
const [rx, ry] = lastControl && lastCommand && "CScs".includes(lastCommand) ? [2 * x - lastControl[0], 2 * y - lastControl[1]] : [x, y];
|
|
2708
|
+
cubic(rx, ry, readNumber() + ox, readNumber() + oy, readNumber() + ox, readNumber() + oy);
|
|
2709
|
+
} else if (upper === "Q" || upper === "T") {
|
|
2710
|
+
let qx, qy;
|
|
2711
|
+
if (upper === "Q") {
|
|
2712
|
+
qx = readNumber() + ox;
|
|
2713
|
+
qy = readNumber() + oy;
|
|
2714
|
+
} else [qx, qy] = lastControl && lastCommand && "QTqt".includes(lastCommand) ? [2 * x - lastControl[0], 2 * y - lastControl[1]] : [x, y];
|
|
2715
|
+
const px = readNumber() + ox, py = readNumber() + oy;
|
|
2716
|
+
const from = [x, y];
|
|
2717
|
+
cubic(from[0] + 2 / 3 * (qx - from[0]), from[1] + 2 / 3 * (qy - from[1]), px + 2 / 3 * (qx - px), py + 2 / 3 * (qy - py), px, py);
|
|
2718
|
+
lastControl = [qx, qy];
|
|
2719
|
+
} else if (upper === "A") {
|
|
2720
|
+
const rx = readNumber(), ry = readNumber(), rotation = readNumber(), large = readFlag(), sweep = readFlag();
|
|
2721
|
+
const px = readNumber() + ox, py = readNumber() + oy;
|
|
2722
|
+
const pieces = arcToCubics(x, y, rx, ry, rotation, large, sweep, px, py);
|
|
2723
|
+
for (const piece of pieces) cubic(...piece);
|
|
2724
|
+
if (!pieces.length) {
|
|
2725
|
+
x = px;
|
|
2726
|
+
y = py;
|
|
2727
|
+
}
|
|
2728
|
+
lastControl = void 0;
|
|
2729
|
+
} else throw Error(`Unsupported SVG path command: ${command}`);
|
|
2730
|
+
}
|
|
2731
|
+
lastCommand = command;
|
|
2732
|
+
}
|
|
2733
|
+
return subpaths.filter((subpath) => subpath.curves.length > 0);
|
|
2734
|
+
}
|
|
2735
|
+
const ellipsePath = (cx, cy, rx, ry) => {
|
|
2736
|
+
const k = .5522847498;
|
|
2737
|
+
return {
|
|
2738
|
+
start: [cx + rx, cy],
|
|
2739
|
+
closed: true,
|
|
2740
|
+
straight: false,
|
|
2741
|
+
curves: [
|
|
2742
|
+
[
|
|
2743
|
+
cx + rx,
|
|
2744
|
+
cy + ry * k,
|
|
2745
|
+
cx + rx * k,
|
|
2746
|
+
cy + ry,
|
|
2747
|
+
cx,
|
|
2748
|
+
cy + ry
|
|
2749
|
+
],
|
|
2750
|
+
[
|
|
2751
|
+
cx - rx * k,
|
|
2752
|
+
cy + ry,
|
|
2753
|
+
cx - rx,
|
|
2754
|
+
cy + ry * k,
|
|
2755
|
+
cx - rx,
|
|
2756
|
+
cy
|
|
2757
|
+
],
|
|
2758
|
+
[
|
|
2759
|
+
cx - rx,
|
|
2760
|
+
cy - ry * k,
|
|
2761
|
+
cx - rx * k,
|
|
2762
|
+
cy - ry,
|
|
2763
|
+
cx,
|
|
2764
|
+
cy - ry
|
|
2765
|
+
],
|
|
2766
|
+
[
|
|
2767
|
+
cx + rx * k,
|
|
2768
|
+
cy - ry,
|
|
2769
|
+
cx + rx,
|
|
2770
|
+
cy - ry * k,
|
|
2771
|
+
cx + rx,
|
|
2772
|
+
cy
|
|
2773
|
+
]
|
|
2774
|
+
]
|
|
2775
|
+
};
|
|
2776
|
+
};
|
|
2777
|
+
const polylinePath = (points, closed) => {
|
|
2778
|
+
const path = {
|
|
2779
|
+
start: points[0],
|
|
2780
|
+
curves: [],
|
|
2781
|
+
closed,
|
|
2782
|
+
straight: true
|
|
2783
|
+
};
|
|
2784
|
+
let [x, y] = points[0];
|
|
2785
|
+
for (const [px, py] of points.slice(1)) {
|
|
2786
|
+
path.curves.push([
|
|
2787
|
+
x,
|
|
2788
|
+
y,
|
|
2789
|
+
px,
|
|
2790
|
+
py,
|
|
2791
|
+
px,
|
|
2792
|
+
py
|
|
2793
|
+
]);
|
|
2794
|
+
x = px;
|
|
2795
|
+
y = py;
|
|
2796
|
+
}
|
|
2797
|
+
if (closed && (x !== points[0][0] || y !== points[0][1])) path.curves.push([
|
|
2798
|
+
x,
|
|
2799
|
+
y,
|
|
2800
|
+
points[0][0],
|
|
2801
|
+
points[0][1],
|
|
2802
|
+
points[0][0],
|
|
2803
|
+
points[0][1]
|
|
2804
|
+
]);
|
|
2805
|
+
return path;
|
|
2806
|
+
};
|
|
2807
|
+
const roundedRectPath = (x, y, w, h, rx, ry) => {
|
|
2808
|
+
rx = Math.min(rx, w / 2);
|
|
2809
|
+
ry = Math.min(ry, h / 2);
|
|
2810
|
+
const k = .5522847498;
|
|
2811
|
+
const curves = [];
|
|
2812
|
+
let cx = x + rx, cy = y;
|
|
2813
|
+
const go = (...piece) => {
|
|
2814
|
+
curves.push(piece);
|
|
2815
|
+
cx = piece[4];
|
|
2816
|
+
cy = piece[5];
|
|
2817
|
+
};
|
|
2818
|
+
go(cx, cy, x + w - rx, y, x + w - rx, y);
|
|
2819
|
+
go(x + w - rx + rx * k, y, x + w, y + ry - ry * k, x + w, y + ry);
|
|
2820
|
+
go(x + w, y + ry, x + w, y + h - ry, x + w, y + h - ry);
|
|
2821
|
+
go(x + w, y + h - ry + ry * k, x + w - rx + rx * k, y + h, x + w - rx, y + h);
|
|
2822
|
+
go(x + w - rx, y + h, x + rx, y + h, x + rx, y + h);
|
|
2823
|
+
go(x + rx - rx * k, y + h, x, y + h - ry + ry * k, x, y + h - ry);
|
|
2824
|
+
go(x, y + h - ry, x, y + ry, x, y + ry);
|
|
2825
|
+
go(x, y + ry - ry * k, x + rx - rx * k, y, x + rx, y);
|
|
2826
|
+
return {
|
|
2827
|
+
start: [x + rx, y],
|
|
2828
|
+
curves,
|
|
2829
|
+
closed: true,
|
|
2830
|
+
straight: false
|
|
2831
|
+
};
|
|
2832
|
+
};
|
|
2833
|
+
function svgToSketchCommands(text, { width, height, layer, existingIds = [] }) {
|
|
2834
|
+
if (typeof text !== "string" || !text.trim()) throw Error("svg must be a non-empty SVG document");
|
|
2835
|
+
if (text.length > 2e5) throw Error(`svg is too large: ${text.length} characters, limit ${MAX_SVG_CHARACTERS}. Split it across several svg commands.`);
|
|
2836
|
+
const root = parseXml(text).children.find((node) => node.name === "svg");
|
|
2837
|
+
if (!root) throw Error("svg must contain an <svg> element");
|
|
2838
|
+
const box = numbers(root.attrs.viewBox);
|
|
2839
|
+
const viewWidth = box.length === 4 ? box[2] : Number.parseFloat(root.attrs.width);
|
|
2840
|
+
const viewHeight = box.length === 4 ? box[3] : Number.parseFloat(root.attrs.height);
|
|
2841
|
+
const originX = box.length === 4 ? box[0] : 0, originY = box.length === 4 ? box[1] : 0;
|
|
2842
|
+
if (!(viewWidth > 0 && viewHeight > 0)) throw Error("<svg> needs a viewBox=\"0 0 W H\" (or width and height)");
|
|
2843
|
+
if (Math.abs(viewWidth / viewHeight - width / height) > .01 * (width / height)) throw Error(`SVG viewBox ${viewWidth}x${viewHeight} does not match the ${width}x${height} sketch ratio. Use viewBox="0 0 ${width} ${height}".`);
|
|
2844
|
+
const byId = /* @__PURE__ */ new Map();
|
|
2845
|
+
const index = (node) => {
|
|
2846
|
+
if (node.attrs.id) byId.set(node.attrs.id, node);
|
|
2847
|
+
node.children.forEach(index);
|
|
2848
|
+
};
|
|
2849
|
+
index(root);
|
|
2850
|
+
const warnings = /* @__PURE__ */ new Set();
|
|
2851
|
+
const used = new Set(existingIds);
|
|
2852
|
+
let counter = 0, clamped = 0;
|
|
2853
|
+
const nextId = (suffix) => {
|
|
2854
|
+
for (;;) {
|
|
2855
|
+
counter++;
|
|
2856
|
+
const id = `svg-${counter}${suffix}`;
|
|
2857
|
+
if (!used.has(id)) {
|
|
2858
|
+
used.add(id);
|
|
2859
|
+
return id;
|
|
2860
|
+
}
|
|
2861
|
+
}
|
|
2862
|
+
};
|
|
2863
|
+
const scale = width / viewWidth;
|
|
2864
|
+
const commands = [];
|
|
2865
|
+
const clamp = (value) => {
|
|
2866
|
+
if (value < 0 || value > 1) clamped++;
|
|
2867
|
+
return Math.max(0, Math.min(1, value));
|
|
2868
|
+
};
|
|
2869
|
+
const norm = (matrix, px, py) => {
|
|
2870
|
+
const [tx, ty] = apply$1(matrix, px, py);
|
|
2871
|
+
return {
|
|
2872
|
+
x: clamp((tx - originX) / viewWidth),
|
|
2873
|
+
y: clamp((ty - originY) / viewHeight)
|
|
2874
|
+
};
|
|
2875
|
+
};
|
|
2876
|
+
const gradientColor = (reference) => {
|
|
2877
|
+
const target = byId.get(/^url\(\s*['"]?#([^)'"]+)['"]?\s*\)/.exec(reference)?.[1] ?? "");
|
|
2878
|
+
if (!target || !/Gradient$/.test(target.name)) throw Error(`SVG paint ${reference} does not reference a gradient defined in the same SVG`);
|
|
2879
|
+
const stops = target.children.filter((child) => child.name === "stop");
|
|
2880
|
+
if (!stops.length) throw Error(`Gradient ${target.attrs.id} has no stops`);
|
|
2881
|
+
const channels = stops.map((stop) => parseColor(stop.attrs["stop-color"] ?? /stop-color\s*:\s*([^;]+)/.exec(stop.attrs.style ?? "")?.[1] ?? "#000000")).filter((color) => color !== "none").map((color) => [
|
|
2882
|
+
1,
|
|
2883
|
+
3,
|
|
2884
|
+
5
|
|
2885
|
+
].map((offset) => Number.parseInt(color.slice(offset, offset + 2), 16)));
|
|
2886
|
+
const mean = [
|
|
2887
|
+
0,
|
|
2888
|
+
1,
|
|
2889
|
+
2
|
|
2890
|
+
].map((channel) => Math.round(channels.reduce((sum, item) => sum + item[channel], 0) / channels.length));
|
|
2891
|
+
warnings.add(`Gradient ${target.attrs.id} was flattened to its average color; stack several bands for a real gradient.`);
|
|
2892
|
+
return `#${mean.map((value) => value.toString(16).padStart(2, "0")).join("")}`;
|
|
2893
|
+
};
|
|
2894
|
+
const paint = (value) => String(value).startsWith("url(") ? gradientColor(value) : parseColor(value);
|
|
2895
|
+
const emit = (subpath, matrix, style, id) => {
|
|
2896
|
+
[subpath.start, ...subpath.curves.flatMap((curve) => [
|
|
2897
|
+
[curve[0], curve[1]],
|
|
2898
|
+
[curve[2], curve[3]],
|
|
2899
|
+
[curve[4], curve[5]]
|
|
2900
|
+
])];
|
|
2901
|
+
const fill = style.fill === "none" ? "none" : paint(style.fill);
|
|
2902
|
+
const stroke = style.stroke === "none" ? "none" : paint(style.stroke);
|
|
2903
|
+
const common = layer === void 0 ? {} : { layer };
|
|
2904
|
+
const strokeWidth = Math.max(1, Math.min(256, (style.strokeWidth || 1) * scale * Math.hypot(matrix[0], matrix[1])));
|
|
2905
|
+
const segments = subpath.curves.length;
|
|
2906
|
+
const closed = subpath.closed;
|
|
2907
|
+
const straightPoints = [subpath.start, ...subpath.curves.map((curve) => [curve[4], curve[5]])];
|
|
2908
|
+
const build = (color, opacity, filled, suffix) => {
|
|
2909
|
+
if (subpath.straight && straightPoints.length >= 2) {
|
|
2910
|
+
const vertices = closed ? straightPoints.slice(0, -1) : straightPoints;
|
|
2911
|
+
if (filled || closed) {
|
|
2912
|
+
if (vertices.length >= 3) return [{
|
|
2913
|
+
op: "stroke",
|
|
2914
|
+
...common,
|
|
2915
|
+
id: nextId(suffix),
|
|
2916
|
+
shape: "polygon",
|
|
2917
|
+
color,
|
|
2918
|
+
opacity,
|
|
2919
|
+
fill: filled,
|
|
2920
|
+
width: strokeWidth,
|
|
2921
|
+
points: vertices.map(([px, py]) => norm(matrix, px, py))
|
|
2922
|
+
}];
|
|
2923
|
+
}
|
|
2924
|
+
if (vertices.length === 2 && !filled) return [{
|
|
2925
|
+
op: "stroke",
|
|
2926
|
+
...common,
|
|
2927
|
+
id: nextId(suffix),
|
|
2928
|
+
shape: "line",
|
|
2929
|
+
color,
|
|
2930
|
+
opacity,
|
|
2931
|
+
fill: false,
|
|
2932
|
+
width: strokeWidth,
|
|
2933
|
+
points: vertices.map(([px, py]) => norm(matrix, px, py))
|
|
2934
|
+
}];
|
|
2935
|
+
if (!filled) {
|
|
2936
|
+
const pieces = [];
|
|
2937
|
+
for (let from = 0; from < vertices.length - 1; from += 1900) pieces.push({
|
|
2938
|
+
op: "stroke",
|
|
2939
|
+
...common,
|
|
2940
|
+
id: nextId(suffix),
|
|
2941
|
+
shape: "pen",
|
|
2942
|
+
color,
|
|
2943
|
+
opacity,
|
|
2944
|
+
fill: false,
|
|
2945
|
+
width: strokeWidth,
|
|
2946
|
+
points: vertices.slice(from, from + 1901).map(([px, py]) => norm(matrix, px, py))
|
|
2947
|
+
});
|
|
2948
|
+
return pieces;
|
|
2949
|
+
}
|
|
2950
|
+
return [];
|
|
2951
|
+
}
|
|
2952
|
+
if (filled && segments > MAX_BEZIER_SEGMENTS) {
|
|
2953
|
+
warnings.add(`A filled path with ${segments} curve segments was flattened to a polygon (more than ${MAX_BEZIER_SEGMENTS} segments cannot stay a Bezier).`);
|
|
2954
|
+
const flat = [subpath.start];
|
|
2955
|
+
let [cx, cy] = subpath.start;
|
|
2956
|
+
for (const [a, b, c1, d, e, f] of subpath.curves) {
|
|
2957
|
+
for (let step = 1; step <= FLATTEN_STEPS; step++) {
|
|
2958
|
+
const t = step / FLATTEN_STEPS, u = 1 - t;
|
|
2959
|
+
flat.push([u * u * u * cx + 3 * u * u * t * a + 3 * u * t * t * c1 + t * t * t * e, u * u * u * cy + 3 * u * u * t * b + 3 * u * t * t * d + t * t * t * f]);
|
|
2960
|
+
}
|
|
2961
|
+
cx = e;
|
|
2962
|
+
cy = f;
|
|
2963
|
+
}
|
|
2964
|
+
if (flat.length > 2e3) throw Error("A filled path is too complex to import; simplify it or split it into several paths.");
|
|
2965
|
+
return [{
|
|
2966
|
+
op: "stroke",
|
|
2967
|
+
...common,
|
|
2968
|
+
id: nextId(suffix),
|
|
2969
|
+
shape: "polygon",
|
|
2970
|
+
color,
|
|
2971
|
+
opacity,
|
|
2972
|
+
fill: true,
|
|
2973
|
+
width: strokeWidth,
|
|
2974
|
+
points: flat.map(([px, py]) => norm(matrix, px, py))
|
|
2975
|
+
}];
|
|
2976
|
+
}
|
|
2977
|
+
const pieces = [];
|
|
2978
|
+
for (let from = 0; from < segments; from += MAX_BEZIER_SEGMENTS) {
|
|
2979
|
+
const chunk = subpath.curves.slice(from, from + MAX_BEZIER_SEGMENTS);
|
|
2980
|
+
const chunkPoints = [from === 0 ? subpath.start : [subpath.curves[from - 1][4], subpath.curves[from - 1][5]], ...chunk.flatMap((curve) => [
|
|
2981
|
+
[curve[0], curve[1]],
|
|
2982
|
+
[curve[2], curve[3]],
|
|
2983
|
+
[curve[4], curve[5]]
|
|
2984
|
+
])];
|
|
2985
|
+
pieces.push({
|
|
2986
|
+
op: "stroke",
|
|
2987
|
+
...common,
|
|
2988
|
+
id: nextId(suffix),
|
|
2989
|
+
shape: "bezier",
|
|
2990
|
+
color,
|
|
2991
|
+
opacity,
|
|
2992
|
+
fill: filled,
|
|
2993
|
+
width: strokeWidth,
|
|
2994
|
+
points: chunkPoints.map(([px, py]) => norm(matrix, px, py))
|
|
2995
|
+
});
|
|
2996
|
+
}
|
|
2997
|
+
return pieces;
|
|
2998
|
+
};
|
|
2999
|
+
if (fill !== "none" && style.fillOpacity * style.opacity > 0) commands.push(...build(fill, style.fillOpacity * style.opacity, true, ""));
|
|
3000
|
+
if (stroke !== "none" && style.strokeOpacity * style.opacity > 0 && style.strokeWidth > 0) commands.push(...build(stroke, style.strokeOpacity * style.opacity, false, "-line"));
|
|
3001
|
+
};
|
|
3002
|
+
const walk = (node, matrix, parentStyle, depth) => {
|
|
3003
|
+
if (depth > 24) throw Error("SVG is nested too deeply");
|
|
3004
|
+
if (UNSUPPORTED.has(node.name)) throw Error(`Unsupported SVG element <${node.name}>. Draw with path, rect, circle, ellipse, line, polyline, polygon, g and use; add text with a native text command.`);
|
|
3005
|
+
if (IGNORED.has(node.name)) return;
|
|
3006
|
+
for (const name of [
|
|
3007
|
+
"clip-path",
|
|
3008
|
+
"mask",
|
|
3009
|
+
"filter"
|
|
3010
|
+
]) if (node.attrs[name] && node.attrs[name] !== "none") throw Error(`Unsupported SVG attribute ${name}. Bake it into the shapes instead.`);
|
|
3011
|
+
const style = styleOf(node, parentStyle);
|
|
3012
|
+
if (style.display === "none") return;
|
|
3013
|
+
const local = multiply(matrix, parseTransform(node.attrs.transform));
|
|
3014
|
+
const n = (name) => Number.parseFloat(node.attrs[name] ?? 0);
|
|
3015
|
+
const finish = (subpaths) => subpaths.forEach((subpath) => emit(subpath, local, style, node.attrs.id));
|
|
3016
|
+
switch (node.name) {
|
|
3017
|
+
case "svg":
|
|
3018
|
+
case "g":
|
|
3019
|
+
case "a":
|
|
3020
|
+
for (const child of node.children) walk(child, local, style, depth + 1);
|
|
3021
|
+
return;
|
|
3022
|
+
case "use": {
|
|
3023
|
+
const href = node.attrs.href ?? node.attrs["xlink:href"];
|
|
3024
|
+
const target = href?.startsWith("#") ? byId.get(href.slice(1)) : void 0;
|
|
3025
|
+
if (!target) throw Error(`<use> must reference an element in the same SVG (${href ?? "missing href"})`);
|
|
3026
|
+
walk(target, multiply(local, [
|
|
3027
|
+
1,
|
|
3028
|
+
0,
|
|
3029
|
+
0,
|
|
3030
|
+
1,
|
|
3031
|
+
n("x"),
|
|
3032
|
+
n("y")
|
|
3033
|
+
]), { ...style }, depth + 1);
|
|
3034
|
+
return;
|
|
3035
|
+
}
|
|
3036
|
+
case "path":
|
|
3037
|
+
finish(parsePathData(node.attrs.d));
|
|
3038
|
+
return;
|
|
3039
|
+
case "rect": {
|
|
3040
|
+
const w = n("width"), h = n("height");
|
|
3041
|
+
if (!(w > 0 && h > 0)) return;
|
|
3042
|
+
const rx = node.attrs.rx !== void 0 ? n("rx") : node.attrs.ry !== void 0 ? n("ry") : 0;
|
|
3043
|
+
const ry = node.attrs.ry !== void 0 ? n("ry") : rx;
|
|
3044
|
+
finish([rx > 0 || ry > 0 ? roundedRectPath(n("x"), n("y"), w, h, rx, ry) : polylinePath([
|
|
3045
|
+
[n("x"), n("y")],
|
|
3046
|
+
[n("x") + w, n("y")],
|
|
3047
|
+
[n("x") + w, n("y") + h],
|
|
3048
|
+
[n("x"), n("y") + h]
|
|
3049
|
+
], true)]);
|
|
3050
|
+
return;
|
|
3051
|
+
}
|
|
3052
|
+
case "circle":
|
|
3053
|
+
if (n("r") > 0) finish([ellipsePath(n("cx"), n("cy"), n("r"), n("r"))]);
|
|
3054
|
+
return;
|
|
3055
|
+
case "ellipse":
|
|
3056
|
+
if (n("rx") > 0 && n("ry") > 0) finish([ellipsePath(n("cx"), n("cy"), n("rx"), n("ry"))]);
|
|
3057
|
+
return;
|
|
3058
|
+
case "line":
|
|
3059
|
+
finish([polylinePath([[n("x1"), n("y1")], [n("x2"), n("y2")]], false)]);
|
|
3060
|
+
return;
|
|
3061
|
+
case "polyline":
|
|
3062
|
+
case "polygon": {
|
|
3063
|
+
const values = numbers(node.attrs.points);
|
|
3064
|
+
if (values.length < 4 || values.length % 2) throw Error(`<${node.name}> needs an even number of coordinates, at least two points`);
|
|
3065
|
+
const pts = [];
|
|
3066
|
+
for (let at = 0; at < values.length; at += 2) pts.push([values[at], values[at + 1]]);
|
|
3067
|
+
finish([polylinePath(pts, node.name === "polygon")]);
|
|
3068
|
+
return;
|
|
3069
|
+
}
|
|
3070
|
+
default: throw Error(`Unsupported SVG element <${node.name}>`);
|
|
3071
|
+
}
|
|
3072
|
+
};
|
|
3073
|
+
walk(root, IDENTITY, {
|
|
3074
|
+
fill: "#000000",
|
|
3075
|
+
stroke: "none",
|
|
3076
|
+
strokeWidth: 1,
|
|
3077
|
+
fillOpacity: 1,
|
|
3078
|
+
strokeOpacity: 1,
|
|
3079
|
+
opacity: 1
|
|
3080
|
+
}, 0);
|
|
3081
|
+
if (!commands.length) throw Error("The SVG contained no drawable shapes");
|
|
3082
|
+
return {
|
|
3083
|
+
commands,
|
|
3084
|
+
warnings: [...warnings],
|
|
3085
|
+
clamped
|
|
3086
|
+
};
|
|
3087
|
+
}
|
|
3088
|
+
function expandSvgCommands(commands, doc, report) {
|
|
3089
|
+
if (!commands.some((command) => command?.op === "svg")) return commands;
|
|
3090
|
+
const width = doc.width ?? 1024, height = doc.height ?? 1024;
|
|
3091
|
+
const ids = new Set(doc.layers.flatMap((item) => item.strokes.map((stroke) => stroke.id).filter(Boolean)));
|
|
3092
|
+
const out = [];
|
|
3093
|
+
let clamped = 0;
|
|
3094
|
+
for (const command of commands) {
|
|
3095
|
+
if (command?.op !== "svg") {
|
|
3096
|
+
out.push(command);
|
|
3097
|
+
if (command?.id) ids.add(command.id);
|
|
3098
|
+
continue;
|
|
3099
|
+
}
|
|
3100
|
+
const result = svgToSketchCommands(command.svg, {
|
|
3101
|
+
width,
|
|
3102
|
+
height,
|
|
3103
|
+
layer: command.layer,
|
|
3104
|
+
existingIds: ids
|
|
3105
|
+
});
|
|
3106
|
+
result.commands.forEach((item) => ids.add(item.id));
|
|
3107
|
+
out.push(...result.commands);
|
|
3108
|
+
clamped += result.clamped;
|
|
3109
|
+
if (report) report.warnings = [.../* @__PURE__ */ new Set([...report.warnings ?? [], ...result.warnings])];
|
|
3110
|
+
}
|
|
3111
|
+
if (report && clamped) report.clampedPoints = (report.clampedPoints ?? 0) + clamped;
|
|
3112
|
+
return out;
|
|
3113
|
+
}
|
|
2324
3114
|
const SKETCH_COMMAND_HELP = {
|
|
2325
3115
|
coordinates: "Assign short meaningful stroke id values for later edits. Text uses two opposite box corners and text content; width is font size in pixels, automatic fitting within the box. Arrow uses two endpoints. Normalized x/y in [0,1]; width is canvas pixels. Read documentId and revision before editing.",
|
|
2326
3116
|
shapes: "line: exactly two endpoints; rectangle/circle (ellipse alias accepted): exactly two opposite bounding-box corners (circle draws an ellipse within that box); polygon: three or more vertices, closed automatically; pen: ordered path points. bezier: start point, then groups of control1/control2/end; use 4 points for one cubic curve, max 64 segments. Prefer bezier for smooth designed curves instead of many pen samples. fill:true closes and fills the curve. fill:true fills rectangle/circle/polygon. Layers and strokes paint in list order, later ones on top. All commands needed for drawing are described here; no source-code search is required.",
|
|
@@ -2330,19 +3120,22 @@ window.__ModuleLoader__.load({
|
|
|
2330
3120
|
layer: "Add: {op:\"layer\",action:\"add\",value:\"name\"}; optional id is the NEW unique integer ID, otherwise allocated automatically. after is the existing insertion anchor, defaults to active layer. Other actions: {op:\"layer\",action:\"select|rename|visible|duplicate|up|down|delete|clear\",id:1,value:\"name\"}; id targets an existing layer.",
|
|
2331
3121
|
curve: "Prefer {op:\"stroke\",shape:\"bezier\",start:{x:0,y:0},segments:[{control1:{x:0.2,y:0},control2:{x:0.8,y:1},end:{x:1,y:1}}],color:\"#123456\"}. Each segment has exactly two controls and an endpoint; no point counting required. Legacy points arrays still accepted. Do not provide both forms.",
|
|
2332
3122
|
object: "{op:\"object\",layer:1,id:\"title\",action:\"update|duplicate|delete\",patch:{color:\"#0088ff\",text:\"Title\"},transform:{dx:0.05,dy:0,scaleX:1,scaleY:1}}. All patch and transform fields optional. Inspect returns object IDs and bounds. Prefer targeted edits over redrawing layers.",
|
|
2333
|
-
resize: "{op:\"resize\",ratio:\"1:1|4:3|3:4|16:9|9:16\"}"
|
|
3123
|
+
resize: "{op:\"resize\",ratio:\"1:1|4:3|3:4|16:9|9:16\"}",
|
|
3124
|
+
svg: "{op:\"svg\",svg:\"<svg viewBox=\\\"0 0 1024 768\\\">...</svg>\",layer:1}. Fastest way to draw: send a whole scene as SVG (path with M L H V C S Q T A Z, rect, circle, ellipse, line, polyline, polygon, g, use, transform, fill/stroke/opacity, style=\"...\"); it becomes native editable strokes. The viewBox must match the canvas size (use the width and height from inspect; 4:3 is 1024x768). Gradients are flattened to their average color, so build glows and skies from stacked bands; text, image, filter, clipPath, mask, pattern and CSS classes are refused. Coordinates outside the canvas are clamped. One svg command may hold up to 200000 characters."
|
|
2334
3125
|
},
|
|
2335
3126
|
limits: {
|
|
2336
3127
|
strokes: MAX_SKETCH_STROKES,
|
|
2337
3128
|
pointsPerStroke: MAX_STROKE_POINTS,
|
|
2338
3129
|
pointsTotal: 2e5,
|
|
2339
|
-
commandsPerBatch: 256
|
|
3130
|
+
commandsPerBatch: 256,
|
|
3131
|
+
svgCharacters: MAX_SVG_CHARACTERS
|
|
2340
3132
|
}
|
|
2341
3133
|
};
|
|
2342
3134
|
const finite = (value, min, max) => typeof value === "number" && Number.isFinite(value) && value >= min && value <= max;
|
|
2343
|
-
function applySketchCommands(source, commands) {
|
|
3135
|
+
function applySketchCommands(source, commands, report) {
|
|
2344
3136
|
if (!Array.isArray(commands) || !commands.length || commands.length > 256) throw Error("Expected 1–256 commands");
|
|
2345
3137
|
let doc = identifyObjects(source);
|
|
3138
|
+
commands = expandSvgCommands(commands, doc, report);
|
|
2346
3139
|
for (let command of commands) {
|
|
2347
3140
|
if (!command || typeof command !== "object") throw Error("Invalid command");
|
|
2348
3141
|
if (command.op === "stroke") command = expandSketchPreset(command);
|
|
@@ -2544,11 +3337,12 @@ window.__ModuleLoader__.load({
|
|
|
2544
3337
|
}
|
|
2545
3338
|
if (request.revision !== current.revision || adapter.busy()) throw Error("Sketch changed or is being edited; inspect again");
|
|
2546
3339
|
let changedObjects;
|
|
3340
|
+
const report = {};
|
|
2547
3341
|
if (request.action === "apply") {
|
|
2548
3342
|
const before = adapter.document();
|
|
2549
3343
|
let next;
|
|
2550
3344
|
try {
|
|
2551
|
-
next = applySketchCommands(before, request.commands);
|
|
3345
|
+
next = applySketchCommands(before, request.commands, report);
|
|
2552
3346
|
} catch (cause) {
|
|
2553
3347
|
const error = new Error(`${cause.message} Correct the batch and retry with the same runId and revision; nothing was applied.`, { cause });
|
|
2554
3348
|
error.code = "SKETCH_INVALID_BATCH";
|
|
@@ -2574,7 +3368,9 @@ window.__ModuleLoader__.load({
|
|
|
2574
3368
|
...changedObjects ? {
|
|
2575
3369
|
changedObjects: changedObjects.slice(0, 100),
|
|
2576
3370
|
changedObjectCount: changedObjects.length
|
|
2577
|
-
} : {}
|
|
3371
|
+
} : {},
|
|
3372
|
+
...report?.warnings?.length ? { warnings: report.warnings } : {},
|
|
3373
|
+
...report?.clampedPoints ? { clampedPoints: report.clampedPoints } : {}
|
|
2578
3374
|
};
|
|
2579
3375
|
completed.set(key, {
|
|
2580
3376
|
fingerprint,
|
|
@@ -4977,6 +5773,8 @@ window.__ModuleLoader__.load({
|
|
|
4977
5773
|
quotaAlertsHint: "低于所选剩余阈值时提醒;自定义可分别设置短周期与长周期。仅使用新鲜数据,不弹窗打断。",
|
|
4978
5774
|
quotaWarning: "{window}额度剩余 {value}%,请留意用量与重置时间。",
|
|
4979
5775
|
speedFastAstraHint: "Astra 约 2 倍速度,消耗更多 Credits",
|
|
5776
|
+
speedUltrafast: "极速 Beta",
|
|
5777
|
+
speedUltrafastHint: "Ultrafast 档,仅账号目录提供时显示(目前为 Pro 500);速度最快,额度和 Credits 消耗更快",
|
|
4980
5778
|
imageEditLocation: "位置",
|
|
4981
5779
|
imageEditReferenceGuide: "本次编辑的干净源图为「{sourceName}」,编号定位参考图为「{referenceName}」。坐标以图片左上角为原点,x 向右、y 向下,百分比相对于整张图片。请查看这两张图片,将它们同时作为编辑工具的参考图,并在工具提示词中完整保留下方编号、位置和修改要求。只修改源图中对应位置的内容;定位参考图上的编号、圆点和引线仅用于定位,不得绘入最终结果。若无法读取两张图片或确定位置,请说明问题,不要猜测或忽略标注。",
|
|
4982
5780
|
nav: "Codex 订阅",
|
|
@@ -5010,7 +5808,8 @@ window.__ModuleLoader__.load({
|
|
|
5010
5808
|
diagnostics: "支持诊断",
|
|
5011
5809
|
diagnosticsLoad: "生成诊断",
|
|
5012
5810
|
diagnosticsLoading: "生成中…",
|
|
5013
|
-
diagnosticsCopy: "
|
|
5811
|
+
diagnosticsCopy: "复制诊断(精简)",
|
|
5812
|
+
diagnosticsCopyFull: "复制完整诊断",
|
|
5014
5813
|
diagnosticsCopied: "已复制",
|
|
5015
5814
|
diagnosticsFailed: "服务端诊断不可用,已生成可复制的本地脱敏诊断。请检查 DSH 服务连接与插件版本。",
|
|
5016
5815
|
feedbackOpen: "反馈问题",
|
|
@@ -5532,6 +6331,8 @@ window.__ModuleLoader__.load({
|
|
|
5532
6331
|
quotaAlertsHint: "Warn at the selected remaining threshold. Custom sets short and long windows separately. Fresh data only; no interrupting popups.",
|
|
5533
6332
|
quotaWarning: "{window}: {value}% remaining. Check usage and reset time.",
|
|
5534
6333
|
speedFastAstraHint: "About 2x speed on Astra; higher Credits use",
|
|
6334
|
+
speedUltrafast: "Ultrafast Beta",
|
|
6335
|
+
speedUltrafastHint: "Ultrafast tier, shown only when your account catalog offers it (Pro 500 today); fastest, uses allowance and Credits faster",
|
|
5535
6336
|
imageEditLocation: "Location",
|
|
5536
6337
|
imageEditReferenceGuide: "The clean source for this edit is \"{sourceName}\"; \"{referenceName}\" is the numbered location reference. Coordinates start at the top-left, x increases rightward and y downward; percentages refer to the whole image. Inspect both images and pass both as references to the image-editing tool. Preserve every number, position and requested change below in the tool prompt. Edit the corresponding content in the clean source; numbers, dots and leader lines on the location reference are guidance only and must not appear in the final result. If either image cannot be read or a location is unclear, explain the problem instead of guessing or ignoring annotations.",
|
|
5537
6338
|
nav: "Codex",
|
|
@@ -5565,7 +6366,8 @@ window.__ModuleLoader__.load({
|
|
|
5565
6366
|
diagnostics: "Support diagnostics",
|
|
5566
6367
|
diagnosticsLoad: "Create report",
|
|
5567
6368
|
diagnosticsLoading: "Creating…",
|
|
5568
|
-
diagnosticsCopy: "Copy report",
|
|
6369
|
+
diagnosticsCopy: "Copy report (short)",
|
|
6370
|
+
diagnosticsCopyFull: "Copy full report",
|
|
5569
6371
|
diagnosticsCopied: "Copied",
|
|
5570
6372
|
diagnosticsFailed: "Server diagnostics unavailable. A local, redacted report is available to copy. Check the DSH service and plugin version.",
|
|
5571
6373
|
feedbackOpen: "Report a problem",
|
|
@@ -5841,6 +6643,10 @@ window.__ModuleLoader__.load({
|
|
|
5841
6643
|
.codexSubscriptionRecover .codexSubscriptionError{flex:1}
|
|
5842
6644
|
.codexSubscriptionRecover button{flex:0 0 auto}
|
|
5843
6645
|
.codexSubscriptionDiagnostics{color:var(--dsw-alias-label-secondary)}
|
|
6646
|
+
.codexSubscriptionDiagnostics ul{margin:0;padding-left:18px;font-size:13px;line-height:20px}
|
|
6647
|
+
.codexSubscriptionDiagnostics li+li{margin-top:6px}
|
|
6648
|
+
.codexSubscriptionDiagnostics li strong{font-weight:600;color:var(--dsw-alias-label-primary)}
|
|
6649
|
+
.codexSubscriptionDiagnostics [role=status]>p{margin:0;font-size:13px}
|
|
5844
6650
|
.codexSubscriptionDiagnostics pre{max-height:240px;margin:0;padding:10px 12px;border-radius:8px;background:var(--dsw-alias-bg-module-platform);overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;font:11px/17px ui-monospace,SFMono-Regular,Consolas,monospace;color:var(--dsw-alias-label-secondary)}
|
|
5845
6651
|
.codexSubscriptionLink{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;min-height:32px;padding:0 13px;border:1px solid var(--dsw-alias-border-l2);border-radius:999px;background:transparent;color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px;text-decoration:none;white-space:nowrap}
|
|
5846
6652
|
.codexSubscriptionLink:hover{background:var(--dsw-alias-bg-module-platform)}
|
|
@@ -7047,7 +7853,6 @@ window.__ModuleLoader__.load({
|
|
|
7047
7853
|
const DEFAULT_SEARCH_PROVIDER = SEARCH_PROVIDER_AUTO;
|
|
7048
7854
|
const SPEED_MODE_FIELD = "speedMode";
|
|
7049
7855
|
const SPEED_MODE_STANDARD = "standard";
|
|
7050
|
-
const SPEED_MODE_FAST = "fast";
|
|
7051
7856
|
const DEFAULT_SPEED_MODE = SPEED_MODE_STANDARD;
|
|
7052
7857
|
const OUTPUT_VERBOSITY_FIELD = "outputVerbosity";
|
|
7053
7858
|
const OUTPUT_VERBOSITY_DEFAULT = "default";
|
|
@@ -7115,7 +7920,11 @@ window.__ModuleLoader__.load({
|
|
|
7115
7920
|
].includes(value) ? value : DEFAULT_OUTPUT_VERBOSITY;
|
|
7116
7921
|
const normalizeInputImageDetail = (value) => INPUT_IMAGE_DETAILS.includes(value) ? value : DEFAULT_INPUT_IMAGE_DETAIL;
|
|
7117
7922
|
const normalizeStreamIdleTimeoutMinutes = (value) => STREAM_IDLE_TIMEOUT_MINUTES.includes(value) ? value : 10;
|
|
7118
|
-
const normalizeSpeedMode = (value) => [
|
|
7923
|
+
const normalizeSpeedMode = (value) => [
|
|
7924
|
+
"standard",
|
|
7925
|
+
"fast",
|
|
7926
|
+
"ultrafast"
|
|
7927
|
+
].includes(value) ? value : DEFAULT_SPEED_MODE;
|
|
7119
7928
|
const normalizeContextMode = (value) => [
|
|
7120
7929
|
"standard",
|
|
7121
7930
|
"extended",
|
|
@@ -7155,6 +7964,7 @@ window.__ModuleLoader__.load({
|
|
|
7155
7964
|
let availableModels = [];
|
|
7156
7965
|
let verbosityModels = [];
|
|
7157
7966
|
let fastModels;
|
|
7967
|
+
let ultrafastModels = [];
|
|
7158
7968
|
let catalogStatus;
|
|
7159
7969
|
let modelsLoading = false;
|
|
7160
7970
|
let modelError = false;
|
|
@@ -7199,6 +8009,7 @@ window.__ModuleLoader__.load({
|
|
|
7199
8009
|
disabledModels: normalizeDisabledModels(value?.[DISABLED_MODELS_FIELD]),
|
|
7200
8010
|
verbosityModels,
|
|
7201
8011
|
fastModels,
|
|
8012
|
+
ultrafastModels,
|
|
7202
8013
|
catalogStatus,
|
|
7203
8014
|
modelsLoading,
|
|
7204
8015
|
modelError,
|
|
@@ -7226,6 +8037,7 @@ window.__ModuleLoader__.load({
|
|
|
7226
8037
|
availableModels = Array.isArray(value?.availableModels) ? value.availableModels : [];
|
|
7227
8038
|
verbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
|
|
7228
8039
|
fastModels = Array.isArray(value?.fastModels) ? value.fastModels : void 0;
|
|
8040
|
+
ultrafastModels = Array.isArray(value?.ultrafastModels) ? value.ultrafastModels : [];
|
|
7229
8041
|
catalogStatus = value?.catalogStatus;
|
|
7230
8042
|
}
|
|
7231
8043
|
fallbackStatus = "ready";
|
|
@@ -7270,6 +8082,8 @@ window.__ModuleLoader__.load({
|
|
|
7270
8082
|
availableModels = Array.isArray(value?.availableModels) ? value.availableModels : [];
|
|
7271
8083
|
verbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
|
|
7272
8084
|
fastModels = Array.isArray(value?.fastModels) ? value.fastModels : void 0;
|
|
8085
|
+
ultrafastModels = Array.isArray(value?.ultrafastModels) ? value.ultrafastModels : [];
|
|
8086
|
+
ultrafastModels = Array.isArray(value?.ultrafastModels) ? value.ultrafastModels : [];
|
|
7273
8087
|
catalogStatus = value?.catalogStatus;
|
|
7274
8088
|
}
|
|
7275
8089
|
} else acceptFallback(value);
|
|
@@ -7293,13 +8107,15 @@ window.__ModuleLoader__.load({
|
|
|
7293
8107
|
const nextAvailableModels = Array.isArray(value?.availableModels) ? value.availableModels : [];
|
|
7294
8108
|
const nextVerbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
|
|
7295
8109
|
const nextFastModels = Array.isArray(value?.fastModels) ? value.fastModels : void 0;
|
|
8110
|
+
const nextUltrafastModels = Array.isArray(value?.ultrafastModels) ? value.ultrafastModels : [];
|
|
7296
8111
|
catalogStatus = value?.catalogStatus;
|
|
7297
|
-
const changed = !sameModels(contextModels, nextContextModels) || !sameModels(availableModels, nextAvailableModels) || !sameModels(verbosityModels, nextVerbosityModels) || JSON.stringify(fastModels) !== JSON.stringify(nextFastModels);
|
|
8112
|
+
const changed = !sameModels(contextModels, nextContextModels) || !sameModels(availableModels, nextAvailableModels) || !sameModels(verbosityModels, nextVerbosityModels) || JSON.stringify(fastModels) !== JSON.stringify(nextFastModels) || JSON.stringify(ultrafastModels) !== JSON.stringify(nextUltrafastModels);
|
|
7298
8113
|
if (changed) {
|
|
7299
8114
|
contextModels = nextContextModels;
|
|
7300
8115
|
availableModels = nextAvailableModels;
|
|
7301
8116
|
verbosityModels = nextVerbosityModels;
|
|
7302
8117
|
fastModels = nextFastModels;
|
|
8118
|
+
ultrafastModels = nextUltrafastModels;
|
|
7303
8119
|
publish();
|
|
7304
8120
|
}
|
|
7305
8121
|
return changed;
|
|
@@ -7660,7 +8476,7 @@ window.__ModuleLoader__.load({
|
|
|
7660
8476
|
}
|
|
7661
8477
|
//#endregion
|
|
7662
8478
|
//#region src/version.js
|
|
7663
|
-
const PACKAGE_VERSION = "2.
|
|
8479
|
+
const PACKAGE_VERSION = "2.4.0";
|
|
7664
8480
|
//#endregion
|
|
7665
8481
|
//#region src/client-recovery.js
|
|
7666
8482
|
async function recoveryCall(rpc, endpoint, payload = {}, timeoutMs = 1e4) {
|
|
@@ -7950,7 +8766,10 @@ window.__ModuleLoader__.load({
|
|
|
7950
8766
|
const modelLabel = currentChoice?.model.name ?? t("selectModel");
|
|
7951
8767
|
const speedSupported = state.current?.provider === "openai-codex" && (preferenceSnapshot.fastModels?.includes(state.current?.model) ?? supportsCodexFastMode(state.current?.model));
|
|
7952
8768
|
const speedWritable = preferenceSnapshot.status === "ready" && preferenceSnapshot.writable === true;
|
|
7953
|
-
const
|
|
8769
|
+
const ultrafastSupported = state.current?.provider === "openai-codex" && (preferenceSnapshot.ultrafastModels ?? []).includes(state.current?.model);
|
|
8770
|
+
const ultrafast = ultrafastSupported && preferenceSnapshot.speedMode === "ultrafast";
|
|
8771
|
+
const fast = ultrafast || speedSupported && preferenceSnapshot.speedMode === "fast";
|
|
8772
|
+
const speedKey = ultrafast ? "speedUltrafast" : fast ? "speedFast" : "speedStandard";
|
|
7954
8773
|
const verbositySupported = state.current?.provider === "openai-codex" && preferenceSnapshot.verbosityModels.includes(state.current?.model);
|
|
7955
8774
|
const verbosityWritable = preferenceSnapshot.status === "ready" && preferenceSnapshot.writable === true;
|
|
7956
8775
|
const verbosityItems = [
|
|
@@ -8158,21 +8977,32 @@ window.__ModuleLoader__.load({
|
|
|
8158
8977
|
className: "codexModelSelectSubmenu",
|
|
8159
8978
|
role: "menu",
|
|
8160
8979
|
"aria-label": t("speedTitle"),
|
|
8161
|
-
children: [
|
|
8162
|
-
|
|
8163
|
-
|
|
8164
|
-
|
|
8165
|
-
|
|
8166
|
-
|
|
8167
|
-
|
|
8168
|
-
|
|
8169
|
-
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
|
|
8980
|
+
children: [
|
|
8981
|
+
option({
|
|
8982
|
+
key: SPEED_MODE_STANDARD,
|
|
8983
|
+
label: t("speedStandard"),
|
|
8984
|
+
description: t("speedStandardHint"),
|
|
8985
|
+
selected: !fast,
|
|
8986
|
+
disabled: !speedWritable,
|
|
8987
|
+
onClick: () => chooseSpeed(SPEED_MODE_STANDARD)
|
|
8988
|
+
}),
|
|
8989
|
+
speedSupported && option({
|
|
8990
|
+
key: "fast",
|
|
8991
|
+
label: t("speedFast"),
|
|
8992
|
+
description: t(state.current?.model === "gpt-6-astra" ? "speedFastAstraHint" : "speedFastHint"),
|
|
8993
|
+
selected: fast && !ultrafast,
|
|
8994
|
+
disabled: !speedWritable,
|
|
8995
|
+
onClick: () => chooseSpeed("fast")
|
|
8996
|
+
}),
|
|
8997
|
+
ultrafastSupported && option({
|
|
8998
|
+
key: "ultrafast",
|
|
8999
|
+
label: t("speedUltrafast"),
|
|
9000
|
+
description: t("speedUltrafastHint"),
|
|
9001
|
+
selected: ultrafast,
|
|
9002
|
+
disabled: !speedWritable,
|
|
9003
|
+
onClick: () => chooseSpeed("ultrafast")
|
|
9004
|
+
})
|
|
9005
|
+
]
|
|
8176
9006
|
});
|
|
8177
9007
|
else if (pane === "verbosity") submenu = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8178
9008
|
className: "codexModelSelectSubmenu",
|
|
@@ -8231,7 +9061,7 @@ window.__ModuleLoader__.load({
|
|
|
8231
9061
|
children: [
|
|
8232
9062
|
cell("model", t("modelLabel"), modelLabel),
|
|
8233
9063
|
reasoning === void 0 ? null : cell("effort", t("effortLabel"), effortLabel),
|
|
8234
|
-
speedSupported && cell("speed", t("speedTitle"), t(
|
|
9064
|
+
(speedSupported || ultrafastSupported) && cell("speed", t("speedTitle"), t(speedKey)),
|
|
8235
9065
|
verbositySupported && cell("verbosity", t("verbosityTitle"), verbosityLabel),
|
|
8236
9066
|
submenu
|
|
8237
9067
|
]
|
|
@@ -9919,6 +10749,40 @@ window.__ModuleLoader__.load({
|
|
|
9919
10749
|
};
|
|
9920
10750
|
}
|
|
9921
10751
|
//#endregion
|
|
10752
|
+
//#region src/diagnostic-compact.js
|
|
10753
|
+
function compactDiagnostic(report) {
|
|
10754
|
+
const summary = report.summary ?? { findings: [] };
|
|
10755
|
+
return {
|
|
10756
|
+
format: "compact-1",
|
|
10757
|
+
plugin: report.version,
|
|
10758
|
+
dsh: report.runtime?.dsh,
|
|
10759
|
+
...report.client?.version && report.client.version !== report.version ? { pluginClient: report.client.version } : {},
|
|
10760
|
+
platform: report.runtime ? `${report.runtime.platform}-${report.runtime.arch}` : void 0,
|
|
10761
|
+
generatedAt: report.generatedAt,
|
|
10762
|
+
account: report.account?.status,
|
|
10763
|
+
catalog: report.catalog ? {
|
|
10764
|
+
source: report.catalog.source,
|
|
10765
|
+
refresh: report.catalog.refresh
|
|
10766
|
+
} : void 0,
|
|
10767
|
+
configuration: report.configuration,
|
|
10768
|
+
findings: summary.findings.map((item) => ({
|
|
10769
|
+
code: item.code,
|
|
10770
|
+
severity: item.severity,
|
|
10771
|
+
...item.code === "recent-failure" ? { failures: item.evidence.map((event) => ({
|
|
10772
|
+
action: event.action,
|
|
10773
|
+
source: event.source,
|
|
10774
|
+
at: new Date(event.observedAt).toISOString()
|
|
10775
|
+
})) } : {}
|
|
10776
|
+
})),
|
|
10777
|
+
capabilities: (report.inspection?.capabilities ?? []).filter((item) => item.readiness !== "not-applicable").map((item) => ({
|
|
10778
|
+
id: item.id,
|
|
10779
|
+
reason: item.reason,
|
|
10780
|
+
...item.latest ? { latest: `${item.latest.action} ${item.latest.status}` } : { latest: "not-verified" }
|
|
10781
|
+
})),
|
|
10782
|
+
...report.client?.status === "unknown" ? { hostCollected: false } : {}
|
|
10783
|
+
};
|
|
10784
|
+
}
|
|
10785
|
+
//#endregion
|
|
9922
10786
|
//#region src/client-diagnostics.jsx
|
|
9923
10787
|
function DiagnosticsCard({ rpc, t, diagnostics }) {
|
|
9924
10788
|
const [report, setReport] = (0, react.useState)();
|
|
@@ -9943,10 +10807,10 @@ window.__ModuleLoader__.load({
|
|
|
9943
10807
|
});
|
|
9944
10808
|
}).finally(() => setBusy(false));
|
|
9945
10809
|
};
|
|
9946
|
-
const copy = () => {
|
|
10810
|
+
const copy = (full = false) => {
|
|
9947
10811
|
if (report === void 0) return;
|
|
9948
10812
|
setCopyError(false);
|
|
9949
|
-
Promise.resolve().then(() => navigator.clipboard.writeText(JSON.stringify(report, null, 2))).then(() => setCopied(true)).catch(() => setCopyError(true));
|
|
10813
|
+
Promise.resolve().then(() => navigator.clipboard.writeText(JSON.stringify(full ? report : compactDiagnostic(report), null, 2))).then(() => setCopied(true)).catch(() => setCopyError(true));
|
|
9950
10814
|
};
|
|
9951
10815
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9952
10816
|
className: "codexSubscriptionCard codexSubscriptionDiagnostics",
|
|
@@ -9972,7 +10836,7 @@ window.__ModuleLoader__.load({
|
|
|
9972
10836
|
report === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
9973
10837
|
type: "button",
|
|
9974
10838
|
variant: "outline",
|
|
9975
|
-
onClick: copy,
|
|
10839
|
+
onClick: () => copy(),
|
|
9976
10840
|
children: copied ? t("diagnosticsCopied") : t("diagnosticsCopy")
|
|
9977
10841
|
}),
|
|
9978
10842
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
@@ -10038,7 +10902,16 @@ window.__ModuleLoader__.load({
|
|
|
10038
10902
|
className: "codexSubscriptionHelp",
|
|
10039
10903
|
children: report.client?.topology?.length ? t("diagnosticsHostCollected") : t("diagnosticsHostUnknown")
|
|
10040
10904
|
}),
|
|
10041
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", { children: [
|
|
10905
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", { children: [
|
|
10906
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: t("diagnosticsDetails") }),
|
|
10907
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
10908
|
+
type: "button",
|
|
10909
|
+
variant: "outline",
|
|
10910
|
+
onClick: () => copy(true),
|
|
10911
|
+
children: t("diagnosticsCopyFull")
|
|
10912
|
+
}),
|
|
10913
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: JSON.stringify(report, null, 2) })
|
|
10914
|
+
] })
|
|
10042
10915
|
] }),
|
|
10043
10916
|
error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10044
10917
|
className: "codexSubscriptionError",
|