drafted 1.17.6 → 1.17.8
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drafted",
|
|
3
|
-
"version": "1.17.
|
|
3
|
+
"version": "1.17.8",
|
|
4
4
|
"description": "Drafted — visual thinking surface for humans and AI agents. Renders HTML, markdown, images, and code as frames on a zoomable canvas, with MCP tools for AI agents and real-time sync for humans.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
export const EXCALIDRAW_MIME = 'application/vnd.excalidraw+json';
|
|
2
2
|
|
|
3
|
+
// Linear elements (arrow/line/freedraw) REQUIRE a `points` array — Excalidraw's scene
|
|
4
|
+
// restore reads points.length and crashes ("Cannot read properties of undefined (reading
|
|
5
|
+
// 'length')") → eternal "Loading scene" spinner. Hand-authored/agent-written scenes
|
|
6
|
+
// routinely omit it (source: "https://excalidraw.com", ids like "el1"), so repair it
|
|
7
|
+
// here: every read (serve) and write path funnels through normalizeExcalidrawScene, so
|
|
8
|
+
// existing broken frames open and new bad writes are fixed before they land.
|
|
9
|
+
const LINEAR_ELEMENT_TYPES = new Set(['arrow', 'line', 'freedraw']);
|
|
10
|
+
|
|
11
|
+
function repairLinearElement(el) {
|
|
12
|
+
if (!LINEAR_ELEMENT_TYPES.has(el.type)) return el;
|
|
13
|
+
const pts = el.points;
|
|
14
|
+
const valid = Array.isArray(pts) && pts.length > 0 &&
|
|
15
|
+
pts.every((p) => Array.isArray(p) && p.length >= 2 && typeof p[0] === 'number' && typeof p[1] === 'number');
|
|
16
|
+
if (valid) return el;
|
|
17
|
+
const w = typeof el.width === 'number' && el.width > 0 ? el.width : 1;
|
|
18
|
+
const h = typeof el.height === 'number' && el.height > 0 ? el.height : 0;
|
|
19
|
+
return { ...el, points: [[0, 0], [w, h]] };
|
|
20
|
+
}
|
|
21
|
+
|
|
3
22
|
export function emptyExcalidrawScene() {
|
|
4
23
|
return {
|
|
5
24
|
type: 'excalidraw',
|
|
@@ -29,7 +48,7 @@ export function normalizeExcalidrawScene(input) {
|
|
|
29
48
|
type: scene.type || 'excalidraw',
|
|
30
49
|
version: scene.version || 2,
|
|
31
50
|
source: scene.source || 'https://drafted.live',
|
|
32
|
-
elements: scene.elements,
|
|
51
|
+
elements: scene.elements.map(repairLinearElement).filter(Boolean),
|
|
33
52
|
appState,
|
|
34
53
|
files,
|
|
35
54
|
};
|
|
@@ -34,6 +34,19 @@ assert.deepStrictEqual(r.elements.map(e => e.id), ['b', 'c'], 'remove beats upse
|
|
|
34
34
|
r = mergeExcalidrawElements(JSON.stringify(base), [{ id: 'e', type: 'text', x: 0 }]);
|
|
35
35
|
assert.strictEqual(r.elements.length, 4, 'parses stored string content');
|
|
36
36
|
|
|
37
|
+
// linear elements without points are repaired (Excalidraw crashes on restore otherwise)
|
|
38
|
+
r = mergeExcalidrawElements({
|
|
39
|
+
...base,
|
|
40
|
+
elements: [
|
|
41
|
+
{ id: 'a1', type: 'arrow', x: 0, y: 0, width: 60, height: 0 },
|
|
42
|
+
{ id: 'l1', type: 'line', x: 0, y: 0, width: 0, height: 0 },
|
|
43
|
+
{ id: 'ok', type: 'arrow', x: 0, y: 0, width: 10, height: 10, points: [[0, 0], [10, 10]] },
|
|
44
|
+
],
|
|
45
|
+
}, []);
|
|
46
|
+
assert.deepStrictEqual(r.elements[0].points, [[0, 0], [60, 0]], 'arrow points synthesized from width');
|
|
47
|
+
assert.deepStrictEqual(r.elements[1].points, [[0, 0], [1, 0]], 'degenerate line gets a fallback line');
|
|
48
|
+
assert.deepStrictEqual(r.elements[2].points, [[0, 0], [10, 10]], 'valid points untouched');
|
|
49
|
+
|
|
37
50
|
// upsert without id is rejected
|
|
38
51
|
assert.throws(() => mergeExcalidrawElements(base, [{ x: 1 }]), /must be an object with an id/);
|
|
39
52
|
|