@browxai/plugin-excalidraw 0.1.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/LICENSE +21 -0
- package/README.md +43 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +203 -0
- package/package.json +61 -0
- package/schema.d.ts +45 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kalebtec
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# @browxai/plugin-excalidraw
|
|
2
|
+
|
|
3
|
+
First-party browxai canvas-app adapter for Excalidraw. Exposes five
|
|
4
|
+
small, useful tools (`excalidraw.get_scene_state`,
|
|
5
|
+
`excalidraw.get_viewport`, `excalidraw.add_element`,
|
|
6
|
+
`excalidraw.delete_element`, `excalidraw.set_scroll`) over the
|
|
7
|
+
`window.excalidrawAPI` global that the host page sets when embedding the
|
|
8
|
+
Excalidraw React component. Each tool is a thin wrapper around an
|
|
9
|
+
`eval_js` round-trip: the plugin builds the appropriate
|
|
10
|
+
`excalidrawAPI.*` expression, dispatches through `eval_js`, and parses
|
|
11
|
+
the value back. When `window.excalidrawAPI` is undefined (Excalidraw not
|
|
12
|
+
mounted, or the host page didn't forward the ref), every tool returns
|
|
13
|
+
the structured `code:"excalidraw-not-loaded"` envelope.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
$ browxai plugin install @browxai/plugin-excalidraw
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The host must have the `eval` and `canvas` capabilities enabled — the
|
|
22
|
+
plugin declares both at the manifest level. Restart the browxai server
|
|
23
|
+
after install (plugin lifecycle is resolved-once-at-server-start).
|
|
24
|
+
|
|
25
|
+
The tools surface as `excalidraw.get_scene_state` (etc.) on MCP
|
|
26
|
+
`tools/list`, and on the SDK as
|
|
27
|
+
`client.plugins.excalidraw.get_scene_state(...)`.
|
|
28
|
+
|
|
29
|
+
## Targeted Excalidraw API surface
|
|
30
|
+
|
|
31
|
+
This plugin pokes the Excalidraw 0.17+ ref API as of 2026-06:
|
|
32
|
+
`excalidrawAPI.getSceneElements()`, `excalidrawAPI.getAppState()`,
|
|
33
|
+
`excalidrawAPI.updateScene({elements, appState})`. These are the
|
|
34
|
+
top-level stable methods of the imperative API. Host pages that embed
|
|
35
|
+
the Excalidraw component must forward the `excalidrawAPI` ref to
|
|
36
|
+
`window.excalidrawAPI` for this plugin to find it; the public
|
|
37
|
+
excalidraw.com deployment does this by default.
|
|
38
|
+
|
|
39
|
+
## Full reference
|
|
40
|
+
|
|
41
|
+
The per-tool reference for this adapter — every op with args, return
|
|
42
|
+
shape, and error codes, plus a usage walkthrough — lives at
|
|
43
|
+
<https://browxai.com/plugins/first-party/>.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
interface ToolResponse {
|
|
2
|
+
readonly content: ReadonlyArray<{
|
|
3
|
+
type: "text";
|
|
4
|
+
text: string;
|
|
5
|
+
} | {
|
|
6
|
+
type: "image";
|
|
7
|
+
data: string;
|
|
8
|
+
mimeType: string;
|
|
9
|
+
}>;
|
|
10
|
+
}
|
|
11
|
+
interface PluginApi {
|
|
12
|
+
readonly namespace: string;
|
|
13
|
+
readonly declaredCapabilities: ReadonlyArray<string>;
|
|
14
|
+
registerTool(name: string, def: {
|
|
15
|
+
description: string;
|
|
16
|
+
inputSchema?: Record<string, any> | undefined;
|
|
17
|
+
}, handler: (args: unknown) => Promise<ToolResponse>): void;
|
|
18
|
+
callTool(name: string, args?: Record<string, unknown>): Promise<ToolResponse>;
|
|
19
|
+
log: {
|
|
20
|
+
info(msg: string, meta?: Record<string, unknown>): void;
|
|
21
|
+
warn(msg: string, meta?: Record<string, unknown>): void;
|
|
22
|
+
error(msg: string, meta?: Record<string, unknown>): void;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export declare const handlers: {
|
|
26
|
+
/** `excalidraw.get_scene_state()` → `{ok, elements:[...], appState:{...}}`. */
|
|
27
|
+
get_scene_state(api: PluginApi, _args: unknown): Promise<ToolResponse>;
|
|
28
|
+
/** `excalidraw.get_viewport()` → `{ok, scrollX, scrollY, zoom}`. */
|
|
29
|
+
get_viewport(api: PluginApi, _args: unknown): Promise<ToolResponse>;
|
|
30
|
+
/** `excalidraw.add_element({type, x, y, width, height, ...})` — append via updateScene. */
|
|
31
|
+
add_element(api: PluginApi, args: unknown): Promise<ToolResponse>;
|
|
32
|
+
/** `excalidraw.delete_element({elementId})` — updateScene without that element. */
|
|
33
|
+
delete_element(api: PluginApi, args: unknown): Promise<ToolResponse>;
|
|
34
|
+
/** `excalidraw.set_scroll({scrollX, scrollY})` — updateScene with appState. */
|
|
35
|
+
set_scroll(api: PluginApi, args: unknown): Promise<ToolResponse>;
|
|
36
|
+
};
|
|
37
|
+
export declare function register(api: PluginApi): void;
|
|
38
|
+
export default register;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
// @browxai/plugin-excalidraw — Excalidraw canvas-app adapter.
|
|
2
|
+
//
|
|
3
|
+
// Surfaces five small, useful tools over the `window.excalidrawAPI`
|
|
4
|
+
// global that the host page sets when embedding the Excalidraw
|
|
5
|
+
// component (the Excalidraw React component takes an `excalidrawAPI`
|
|
6
|
+
// ref callback; community deployments typically forward it to
|
|
7
|
+
// `window.excalidrawAPI`). Each tool routes through `eval_js`.
|
|
8
|
+
//
|
|
9
|
+
// Targeted API surface (Excalidraw 0.17+, current as of 2026-06):
|
|
10
|
+
// - excalidrawAPI.getSceneElements() → Element[]
|
|
11
|
+
// - excalidrawAPI.getAppState() → { viewBackgroundColor, viewModeEnabled, zoom, scrollX, scrollY, ... }
|
|
12
|
+
// - excalidrawAPI.updateScene({elements?, appState?})
|
|
13
|
+
//
|
|
14
|
+
// When `window.excalidrawAPI` is undefined (Excalidraw not mounted, or
|
|
15
|
+
// the host page didn't expose the ref), every tool returns the
|
|
16
|
+
// structured `code:"excalidraw-not-loaded"` envelope.
|
|
17
|
+
const json = (obj) => ({
|
|
18
|
+
content: [{ type: "text", text: JSON.stringify(obj, null, 2) }],
|
|
19
|
+
});
|
|
20
|
+
const NOT_LOADED = {
|
|
21
|
+
ok: false,
|
|
22
|
+
error: "Excalidraw not loaded — open the app first OR the surface is not exposed on this version of the app",
|
|
23
|
+
code: "excalidraw-not-loaded",
|
|
24
|
+
};
|
|
25
|
+
const badArg = (which) => ({
|
|
26
|
+
ok: false,
|
|
27
|
+
error: `bad-arg: missing or invalid \`${which}\``,
|
|
28
|
+
code: "bad-arg",
|
|
29
|
+
});
|
|
30
|
+
function parseEvalEnvelope(res) {
|
|
31
|
+
const first = res.content[0];
|
|
32
|
+
if (!first || first.type !== "text") {
|
|
33
|
+
return { ok: false, error: "eval_js returned no text content" };
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
return JSON.parse(first.text);
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
return { ok: false, error: `eval_js envelope parse failure: ${e.message}` };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function runEval(api, expr) {
|
|
43
|
+
const res = await api.callTool("eval_js", { expr });
|
|
44
|
+
const env = parseEvalEnvelope(res);
|
|
45
|
+
if (!env.ok)
|
|
46
|
+
return { ok: false, error: env.error ?? "eval_js failed" };
|
|
47
|
+
return { ok: true, value: env.value };
|
|
48
|
+
}
|
|
49
|
+
async function excalidrawLoaded(api) {
|
|
50
|
+
const r = await runEval(api, `(typeof window !== "undefined" && typeof window.excalidrawAPI !== "undefined" && window.excalidrawAPI !== null)`);
|
|
51
|
+
return r.ok && r.value === true;
|
|
52
|
+
}
|
|
53
|
+
export const handlers = {
|
|
54
|
+
/** `excalidraw.get_scene_state()` → `{ok, elements:[...], appState:{...}}`. */
|
|
55
|
+
async get_scene_state(api, _args) {
|
|
56
|
+
if (!(await excalidrawLoaded(api)))
|
|
57
|
+
return json(NOT_LOADED);
|
|
58
|
+
const expr = `(() => {
|
|
59
|
+
const a = window.excalidrawAPI;
|
|
60
|
+
const els = (a.getSceneElements ? a.getSceneElements() : []) || [];
|
|
61
|
+
const st = (a.getAppState ? a.getAppState() : {}) || {};
|
|
62
|
+
return {
|
|
63
|
+
elements: els.map(e => ({
|
|
64
|
+
id: e.id,
|
|
65
|
+
type: e.type,
|
|
66
|
+
x: e.x,
|
|
67
|
+
y: e.y,
|
|
68
|
+
width: e.width,
|
|
69
|
+
height: e.height,
|
|
70
|
+
})),
|
|
71
|
+
appState: {
|
|
72
|
+
viewBackgroundColor: st.viewBackgroundColor,
|
|
73
|
+
viewModeEnabled: !!st.viewModeEnabled,
|
|
74
|
+
zoom: st.zoom,
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
})()`;
|
|
78
|
+
const r = await runEval(api, expr);
|
|
79
|
+
if (!r.ok)
|
|
80
|
+
return json({ ok: false, error: r.error, code: "eval-failed" });
|
|
81
|
+
return json({ ok: true, ...r.value });
|
|
82
|
+
},
|
|
83
|
+
/** `excalidraw.get_viewport()` → `{ok, scrollX, scrollY, zoom}`. */
|
|
84
|
+
async get_viewport(api, _args) {
|
|
85
|
+
if (!(await excalidrawLoaded(api)))
|
|
86
|
+
return json(NOT_LOADED);
|
|
87
|
+
const expr = `(() => {
|
|
88
|
+
const a = window.excalidrawAPI;
|
|
89
|
+
const st = (a.getAppState ? a.getAppState() : {}) || {};
|
|
90
|
+
const zoomVal = st.zoom && typeof st.zoom === "object" ? st.zoom.value : st.zoom;
|
|
91
|
+
return { scrollX: st.scrollX || 0, scrollY: st.scrollY || 0, zoom: zoomVal || 1 };
|
|
92
|
+
})()`;
|
|
93
|
+
const r = await runEval(api, expr);
|
|
94
|
+
if (!r.ok)
|
|
95
|
+
return json({ ok: false, error: r.error, code: "eval-failed" });
|
|
96
|
+
return json({ ok: true, ...r.value });
|
|
97
|
+
},
|
|
98
|
+
/** `excalidraw.add_element({type, x, y, width, height, ...})` — append via updateScene. */
|
|
99
|
+
async add_element(api, args) {
|
|
100
|
+
const a = (args ?? {});
|
|
101
|
+
if (typeof a.type !== "string" || a.type.length === 0)
|
|
102
|
+
return json(badArg("type"));
|
|
103
|
+
if (typeof a.x !== "number")
|
|
104
|
+
return json(badArg("x"));
|
|
105
|
+
if (typeof a.y !== "number")
|
|
106
|
+
return json(badArg("y"));
|
|
107
|
+
if (typeof a.width !== "number")
|
|
108
|
+
return json(badArg("width"));
|
|
109
|
+
if (typeof a.height !== "number")
|
|
110
|
+
return json(badArg("height"));
|
|
111
|
+
if (!(await excalidrawLoaded(api)))
|
|
112
|
+
return json(NOT_LOADED);
|
|
113
|
+
const elementJson = JSON.stringify(a);
|
|
114
|
+
const expr = `(() => {
|
|
115
|
+
const apiRef = window.excalidrawAPI;
|
|
116
|
+
const before = (apiRef.getSceneElements ? apiRef.getSceneElements() : []) || [];
|
|
117
|
+
const seed = ${elementJson};
|
|
118
|
+
// Excalidraw needs every element to carry a stable id; mint one
|
|
119
|
+
// if the caller didn't supply it. The crypto.randomUUID() path
|
|
120
|
+
// matches what Excalidraw itself does on internal creation.
|
|
121
|
+
const id = seed.id || (typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : "el-" + Date.now() + "-" + Math.random().toString(36).slice(2));
|
|
122
|
+
const newEl = Object.assign({}, seed, { id });
|
|
123
|
+
apiRef.updateScene({ elements: before.concat([newEl]) });
|
|
124
|
+
return { elementId: id };
|
|
125
|
+
})()`;
|
|
126
|
+
const r = await runEval(api, expr);
|
|
127
|
+
if (!r.ok)
|
|
128
|
+
return json({ ok: false, error: r.error, code: "eval-failed" });
|
|
129
|
+
const v = r.value;
|
|
130
|
+
return json({ ok: true, elementId: v.elementId });
|
|
131
|
+
},
|
|
132
|
+
/** `excalidraw.delete_element({elementId})` — updateScene without that element. */
|
|
133
|
+
async delete_element(api, args) {
|
|
134
|
+
const a = (args ?? {});
|
|
135
|
+
if (typeof a.elementId !== "string" || a.elementId.length === 0)
|
|
136
|
+
return json(badArg("elementId"));
|
|
137
|
+
if (!(await excalidrawLoaded(api)))
|
|
138
|
+
return json(NOT_LOADED);
|
|
139
|
+
const id = JSON.stringify(a.elementId);
|
|
140
|
+
const expr = `(() => {
|
|
141
|
+
const apiRef = window.excalidrawAPI;
|
|
142
|
+
const before = (apiRef.getSceneElements ? apiRef.getSceneElements() : []) || [];
|
|
143
|
+
const after = before.filter(e => e.id !== ${id});
|
|
144
|
+
apiRef.updateScene({ elements: after });
|
|
145
|
+
return { removed: before.length - after.length };
|
|
146
|
+
})()`;
|
|
147
|
+
const r = await runEval(api, expr);
|
|
148
|
+
if (!r.ok)
|
|
149
|
+
return json({ ok: false, error: r.error, code: "eval-failed" });
|
|
150
|
+
const v = r.value;
|
|
151
|
+
if (v.removed === 0)
|
|
152
|
+
return json({
|
|
153
|
+
ok: false,
|
|
154
|
+
error: `element not found: ${a.elementId}`,
|
|
155
|
+
code: "element-not-found",
|
|
156
|
+
});
|
|
157
|
+
return json({ ok: true, elementId: a.elementId });
|
|
158
|
+
},
|
|
159
|
+
/** `excalidraw.set_scroll({scrollX, scrollY})` — updateScene with appState. */
|
|
160
|
+
async set_scroll(api, args) {
|
|
161
|
+
const a = (args ?? {});
|
|
162
|
+
if (typeof a.scrollX !== "number")
|
|
163
|
+
return json(badArg("scrollX"));
|
|
164
|
+
if (typeof a.scrollY !== "number")
|
|
165
|
+
return json(badArg("scrollY"));
|
|
166
|
+
if (!(await excalidrawLoaded(api)))
|
|
167
|
+
return json(NOT_LOADED);
|
|
168
|
+
const expr = `(() => {
|
|
169
|
+
const apiRef = window.excalidrawAPI;
|
|
170
|
+
const cur = (apiRef.getAppState ? apiRef.getAppState() : {}) || {};
|
|
171
|
+
apiRef.updateScene({ appState: Object.assign({}, cur, { scrollX: ${a.scrollX}, scrollY: ${a.scrollY} }) });
|
|
172
|
+
return { scrollX: ${a.scrollX}, scrollY: ${a.scrollY} };
|
|
173
|
+
})()`;
|
|
174
|
+
const r = await runEval(api, expr);
|
|
175
|
+
if (!r.ok)
|
|
176
|
+
return json({ ok: false, error: r.error, code: "eval-failed" });
|
|
177
|
+
return json({ ok: true, scrollX: a.scrollX, scrollY: a.scrollY });
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
export function register(api) {
|
|
181
|
+
api.log.info("excalidraw plugin: registering tools", { namespace: api.namespace });
|
|
182
|
+
api.registerTool(`${api.namespace}.get_scene_state`, {
|
|
183
|
+
description: "Read `excalidrawAPI.getSceneElements()` + `excalidrawAPI.getAppState()` — returns `{ok, elements:[{id,type,x,y,width,height}], appState:{viewBackgroundColor, viewModeEnabled, zoom}}`. App-not-loaded surfaces `code:'excalidraw-not-loaded'`.",
|
|
184
|
+
inputSchema: {},
|
|
185
|
+
}, (args) => handlers.get_scene_state(api, args));
|
|
186
|
+
api.registerTool(`${api.namespace}.get_viewport`, {
|
|
187
|
+
description: "Derive viewport from `appState.scrollX/scrollY/zoom` — returns `{ok, scrollX, scrollY, zoom}`. App-not-loaded surfaces `code:'excalidraw-not-loaded'`.",
|
|
188
|
+
inputSchema: {},
|
|
189
|
+
}, (args) => handlers.get_viewport(api, args));
|
|
190
|
+
api.registerTool(`${api.namespace}.add_element`, {
|
|
191
|
+
description: "Append a scene element via `excalidrawAPI.updateScene({elements: [...existing, new]})`. Required: `type, x, y, width, height`; any extra fields are passed through to Excalidraw. Returns `{ok, elementId}` — id minted via `crypto.randomUUID()` if not supplied. App-not-loaded / bad-arg surface structured errors.",
|
|
192
|
+
inputSchema: {},
|
|
193
|
+
}, (args) => handlers.add_element(api, args));
|
|
194
|
+
api.registerTool(`${api.namespace}.delete_element`, {
|
|
195
|
+
description: "Remove the element with `elementId` from the scene via `excalidrawAPI.updateScene`. Returns `{ok, elementId}` on success, `{code:'element-not-found'}` if the id isn't present.",
|
|
196
|
+
inputSchema: {},
|
|
197
|
+
}, (args) => handlers.delete_element(api, args));
|
|
198
|
+
api.registerTool(`${api.namespace}.set_scroll`, {
|
|
199
|
+
description: "Set `appState.scrollX/scrollY` via `excalidrawAPI.updateScene`. Returns `{ok, scrollX, scrollY}`.",
|
|
200
|
+
inputSchema: {},
|
|
201
|
+
}, (args) => handlers.set_scroll(api, args));
|
|
202
|
+
}
|
|
203
|
+
export default register;
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@browxai/plugin-excalidraw",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Excalidraw canvas-app adapter plugin for browxai — surfaces scene/viewport/add/delete/scroll over the `window.excalidrawAPI` page-side global.",
|
|
5
|
+
"author": "Kalebtec",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"browxai",
|
|
10
|
+
"browxai-plugin",
|
|
11
|
+
"excalidraw",
|
|
12
|
+
"canvas",
|
|
13
|
+
"mcp",
|
|
14
|
+
"browser-automation",
|
|
15
|
+
"ai-agent"
|
|
16
|
+
],
|
|
17
|
+
"homepage": "https://browxai.com/plugins/first-party/",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/kalebteccom/browxai.git",
|
|
21
|
+
"directory": "packages/plugins/excalidraw"
|
|
22
|
+
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/kalebteccom/browxai/issues"
|
|
25
|
+
},
|
|
26
|
+
"main": "dist/index.js",
|
|
27
|
+
"types": "dist/index.d.ts",
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"schema.d.ts",
|
|
31
|
+
"LICENSE"
|
|
32
|
+
],
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public",
|
|
35
|
+
"provenance": true
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsc -p tsconfig.json",
|
|
39
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
40
|
+
"test": "vitest run"
|
|
41
|
+
},
|
|
42
|
+
"browxai": {
|
|
43
|
+
"apiVersion": "1.0.0",
|
|
44
|
+
"browxaiVersion": "^0.7.0",
|
|
45
|
+
"namespace": "excalidraw",
|
|
46
|
+
"register": "dist/index.js",
|
|
47
|
+
"capabilities": [
|
|
48
|
+
"eval",
|
|
49
|
+
"canvas"
|
|
50
|
+
],
|
|
51
|
+
"trust": "kalebtec",
|
|
52
|
+
"dependsOn": []
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=20"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"typescript": "^5.5.0",
|
|
59
|
+
"vitest": "^2.0.0"
|
|
60
|
+
}
|
|
61
|
+
}
|
package/schema.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Typed SDK overlay for `@browxai/plugin-excalidraw` consumers.
|
|
2
|
+
|
|
3
|
+
interface ExcalidrawBrowxaiResult {
|
|
4
|
+
readonly content: ReadonlyArray<
|
|
5
|
+
{ type: "text"; text: string } | { type: "image"; data: string; mimeType: string }
|
|
6
|
+
>;
|
|
7
|
+
readonly data?: Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ExcalidrawElement {
|
|
11
|
+
readonly id: string;
|
|
12
|
+
readonly type: string;
|
|
13
|
+
readonly x: number;
|
|
14
|
+
readonly y: number;
|
|
15
|
+
readonly width: number;
|
|
16
|
+
readonly height: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ExcalidrawAppState {
|
|
20
|
+
readonly viewBackgroundColor: string;
|
|
21
|
+
readonly viewModeEnabled: boolean;
|
|
22
|
+
readonly zoom: { value: number };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface ExcalidrawPluginSchema {
|
|
26
|
+
readonly excalidraw: {
|
|
27
|
+
/** Read scene elements + app state — `{ok, elements:[...], appState:{...}}`. */
|
|
28
|
+
get_scene_state(args?: Record<string, never>): Promise<ExcalidrawBrowxaiResult>;
|
|
29
|
+
/** Derive viewport from `appState.scrollX/Y/zoom` — `{ok, scrollX, scrollY, zoom}`. */
|
|
30
|
+
get_viewport(args?: Record<string, never>): Promise<ExcalidrawBrowxaiResult>;
|
|
31
|
+
/** Append an element via `excalidrawAPI.updateScene({elements:[...existing, new]})`. */
|
|
32
|
+
add_element(args: {
|
|
33
|
+
type: string;
|
|
34
|
+
x: number;
|
|
35
|
+
y: number;
|
|
36
|
+
width: number;
|
|
37
|
+
height: number;
|
|
38
|
+
[key: string]: unknown;
|
|
39
|
+
}): Promise<ExcalidrawBrowxaiResult>;
|
|
40
|
+
/** Remove an element by id via `excalidrawAPI.updateScene`. */
|
|
41
|
+
delete_element(args: { elementId: string }): Promise<ExcalidrawBrowxaiResult>;
|
|
42
|
+
/** Set `appState.scrollX/Y` via `excalidrawAPI.updateScene`. */
|
|
43
|
+
set_scroll(args: { scrollX: number; scrollY: number }): Promise<ExcalidrawBrowxaiResult>;
|
|
44
|
+
};
|
|
45
|
+
}
|