agentic-canvas 0.2.0 → 0.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/dist/cli.js CHANGED
@@ -5,16 +5,16 @@ import {
5
5
  operatorActor,
6
6
  runMcp,
7
7
  svgToPng
8
- } from "./chunk-KEMOXKBY.js";
8
+ } from "./chunk-TSWXD4YG.js";
9
9
  import {
10
10
  openLocalStore
11
11
  } from "./chunk-UKST5A57.js";
12
12
  import {
13
13
  CanvasService
14
- } from "./chunk-W7NRP3EX.js";
14
+ } from "./chunk-J52RPFRP.js";
15
15
  import {
16
16
  CanvasError
17
- } from "./chunk-GGQPE65T.js";
17
+ } from "./chunk-JZA525X5.js";
18
18
  import "./chunk-NWQED42L.js";
19
19
 
20
20
  // src/cli.ts
@@ -29,9 +29,11 @@ Usage: ${BRAND.command} [--dir <path>] <command> [flags]
29
29
 
30
30
  Commands:
31
31
  new [--id <id>] [--title <t>] Make a board.
32
+ list List the boards with their titles.
32
33
  read <board> Print the board as JSON.
33
34
  add <board> --type <t> --x <n> --y <n> Add a shape. Also: --w --h --text --fill --stroke --src --id.
34
35
  connect <board> <from> <to> [--text <t>] Join two shapes with an arrow.
36
+ update <board> <element> [--x --y --w --h --text --fill --stroke] Change fields of an element. Resize with --w and --h.
35
37
  move <board> <element> --dx <n> --dy <n> Move an element or a group.
36
38
  rm <board> <element> Delete an element.
37
39
  flow <board> --text <t> | --file <p> Draw a flowchart from text ("A -> B: label"). Use --file - for stdin.
@@ -118,6 +120,9 @@ async function run(argv) {
118
120
  case "new":
119
121
  need(0, "[--id <id>] [--title <t>]");
120
122
  return print(await service.create(actor(), { id: v.id, title: v.title }));
123
+ case "list":
124
+ need(0, "");
125
+ return print({ boards: await service.list() });
121
126
  case "read":
122
127
  need(1, "<board>");
123
128
  return print(await service.read(board));
@@ -127,6 +132,11 @@ async function run(argv) {
127
132
  case "connect":
128
133
  need(3, "<board> <from> <to> [--text <t>]");
129
134
  return print(await service.connect(board, { id: v.id, from: { id: rest[0] }, to: { id: rest[1] }, text: v.text }, actor()));
135
+ case "update": {
136
+ need(2, "<board> <element> [--x <n>] [--y <n>] [--w <n>] [--h <n>] [--text <t>] [--fill <c>] [--stroke <c>]");
137
+ const patch = Object.fromEntries(Object.entries({ x: num(v.x), y: num(v.y), w: num(v.w), h: num(v.h), text: v.text, fill: v.fill, stroke: v.stroke }).filter(([, value]) => value !== void 0));
138
+ return print(await service.update(board, rest[0], patch, actor()));
139
+ }
130
140
  case "move":
131
141
  need(2, "<board> <element> --dx <n> --dy <n>");
132
142
  return print(await service.move(board, rest[0], num(v.dx) ?? Number.NaN, num(v.dy) ?? Number.NaN, actor()));
@@ -0,0 +1,119 @@
1
+ import { E as ErrorCode, B as BoardData, S as ShapeType, a as Shape, b as Endpoint, C as Connector } from './read-Bdg1uiFC.js';
2
+ import { PrincipalKind } from 'agentic-identity';
3
+ import 'yjs';
4
+ import 'zod';
5
+
6
+ interface ClientOptions {
7
+ /** The API root, for example `https://canvas.example.com/api/v1/canvas`. */
8
+ baseUrl: string;
9
+ /** A bearer token. The token sets the actor, the kind, and the role. */
10
+ token: string;
11
+ /** A custom `fetch`. Defaults to the global one. */
12
+ fetch?: typeof fetch;
13
+ }
14
+ /** Options for every call. */
15
+ interface CallOptions {
16
+ signal?: AbortSignal;
17
+ }
18
+ interface ShapeInput {
19
+ id?: string;
20
+ type: ShapeType;
21
+ x: number;
22
+ y: number;
23
+ w?: number;
24
+ h?: number;
25
+ text?: string;
26
+ fill?: string;
27
+ stroke?: string;
28
+ /** A `data:` URL or a `blob:` ref, for an image. */
29
+ src?: string;
30
+ }
31
+ interface ConnectorInput {
32
+ id?: string;
33
+ from: Endpoint;
34
+ to: Endpoint;
35
+ text?: string;
36
+ startArrow?: boolean;
37
+ endArrow?: boolean;
38
+ stroke?: string;
39
+ }
40
+ type ShapePatch = Partial<Pick<ShapeInput, "x" | "y" | "w" | "h" | "text" | "fill" | "stroke" | "src">>;
41
+ type ConnectorPatch = Partial<Pick<ConnectorInput, "from" | "to" | "text" | "startArrow" | "endArrow" | "stroke">>;
42
+ interface ImageInfo {
43
+ id: string;
44
+ ref: string;
45
+ type: string;
46
+ size: number;
47
+ /** False when the same bytes were stored before. */
48
+ created: boolean;
49
+ }
50
+ /**
51
+ * A failed call. `code` is the API error code, such as `NOT_FOUND`, `UNAUTHORIZED`, or `INVALID`. `status` is the HTTP status.
52
+ * A reply that is not the API's error shape has code `HTTP_ERROR`. A call that never got a reply has code `NETWORK` and status 0.
53
+ */
54
+ type ApiErrorCode = ErrorCode | "UNAUTHORIZED" | "NOT_CONFIGURED" | "TOO_LARGE" | "UNSUPPORTED_TYPE" | "UPGRADE_REQUIRED" | "INTERNAL" | "NETWORK" | "HTTP_ERROR" | (string & {});
55
+ declare class CanvasApiError extends Error {
56
+ readonly code: ApiErrorCode;
57
+ readonly status: number;
58
+ constructor(code: ApiErrorCode, message: string, status: number);
59
+ }
60
+ interface CanvasClient {
61
+ /** Who the token stands for. */
62
+ me(options?: CallOptions): Promise<{
63
+ actor: string;
64
+ kind: PrincipalKind;
65
+ role: "editor" | "viewer";
66
+ }>;
67
+ /** The first 100 boards, with titles. */
68
+ listBoards(options?: CallOptions): Promise<{
69
+ boards: {
70
+ id: string;
71
+ title: string;
72
+ }[];
73
+ }>;
74
+ createBoard(input?: {
75
+ id?: string;
76
+ title?: string;
77
+ }, options?: CallOptions): Promise<{
78
+ id: string;
79
+ title: string;
80
+ }>;
81
+ readBoard(id: string, options?: CallOptions): Promise<BoardData & {
82
+ id: string;
83
+ }>;
84
+ /** The board as an SVG document. */
85
+ exportSvg(id: string, options?: CallOptions): Promise<string>;
86
+ addShape(id: string, shape: ShapeInput, options?: CallOptions): Promise<Shape>;
87
+ addConnector(id: string, connector: ConnectorInput, options?: CallOptions): Promise<Connector>;
88
+ /** Draw a flowchart from text such as `A -> B: label`. Returns the new ids. */
89
+ drawFlow(id: string, text: string, options?: CallOptions): Promise<{
90
+ nodes: string[];
91
+ edges: string[];
92
+ }>;
93
+ /** Change fields of one shape or connector, such as its size or text. The patch holds at least one field. */
94
+ update(id: string, element: string, patch: ShapePatch | ConnectorPatch, options?: CallOptions): Promise<Shape | Connector>;
95
+ /** Move an element. Returns the ids that moved: a shape takes its connectors with it. */
96
+ move(id: string, element: string, dx: number, dy: number, options?: CallOptions): Promise<{
97
+ moved: string[];
98
+ }>;
99
+ /** Remove an element. Returns the ids removed. */
100
+ remove(id: string, element: string, options?: CallOptions): Promise<{
101
+ removed: string[];
102
+ }>;
103
+ uploadImage(bytes: Uint8Array | ArrayBuffer | Blob, options?: CallOptions): Promise<ImageInfo>;
104
+ /** The bytes of a stored image, and its content type. */
105
+ getImage(id: string, options?: CallOptions): Promise<{
106
+ bytes: Uint8Array;
107
+ type: string;
108
+ }>;
109
+ /** The stored board as a Yjs update. Only a server with live rooms serves it. */
110
+ state(id: string, options?: CallOptions): Promise<Uint8Array>;
111
+ /** Merge a live room's Yjs update into the stored board. Only a server with live rooms serves it. */
112
+ checkpoint(id: string, update: Uint8Array, options?: CallOptions): Promise<{
113
+ elements: number;
114
+ fixed: string[];
115
+ }>;
116
+ }
117
+ declare function createClient(options: ClientOptions): CanvasClient;
118
+
119
+ export { type ApiErrorCode, type CallOptions, CanvasApiError, type CanvasClient, type ClientOptions, type ConnectorInput, type ConnectorPatch, type ImageInfo, type ShapeInput, type ShapePatch, createClient };
package/dist/client.js ADDED
@@ -0,0 +1,80 @@
1
+ // src/client.ts
2
+ var CanvasApiError = class extends Error {
3
+ constructor(code, message, status) {
4
+ super(message);
5
+ this.code = code;
6
+ this.status = status;
7
+ this.name = "CanvasApiError";
8
+ }
9
+ code;
10
+ status;
11
+ };
12
+ function createClient(options) {
13
+ const { token } = options;
14
+ const base = options.baseUrl.replace(/\/+$/, "");
15
+ if (!token) throw new TypeError("token is required");
16
+ const doFetch = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
17
+ const seg = encodeURIComponent;
18
+ async function send(method, path, init, call) {
19
+ const headers = { authorization: `Bearer ${token}` };
20
+ if (init.json !== void 0) headers["content-type"] = "application/json";
21
+ if (init.contentType) headers["content-type"] = init.contentType;
22
+ let response;
23
+ try {
24
+ response = await doFetch(`${base}${path}`, {
25
+ method,
26
+ headers,
27
+ body: init.json === void 0 ? init.body : JSON.stringify(init.json),
28
+ signal: call?.signal
29
+ });
30
+ } catch (error) {
31
+ if (call?.signal?.aborted) throw error;
32
+ throw new CanvasApiError("NETWORK", error instanceof Error ? error.message : "the request failed", 0);
33
+ }
34
+ if (response.ok) return response;
35
+ let code = "HTTP_ERROR";
36
+ let message = `the server answered ${response.status}`;
37
+ try {
38
+ const { error } = await response.json();
39
+ if (typeof error?.code === "string") code = error.code;
40
+ if (typeof error?.message === "string") message = error.message;
41
+ } catch {
42
+ if (call?.signal?.aborted) throw call.signal.reason;
43
+ }
44
+ throw new CanvasApiError(code, message, response.status);
45
+ }
46
+ const parse = async (response, call) => {
47
+ try {
48
+ return await response.json();
49
+ } catch (error) {
50
+ if (call?.signal?.aborted) throw error;
51
+ throw new CanvasApiError("HTTP_ERROR", "the server did not answer with JSON", response.status);
52
+ }
53
+ };
54
+ const json = async (method, path, body, call) => parse(await send(method, path, { json: body }, call), call);
55
+ const bytes = async (response) => new Uint8Array(await response.arrayBuffer());
56
+ return {
57
+ me: (o) => json("GET", "/me", void 0, o),
58
+ listBoards: (o) => json("GET", "/boards", void 0, o),
59
+ createBoard: (input = {}, o) => json("POST", "/boards", input, o),
60
+ readBoard: (id, o) => json("GET", `/boards/${seg(id)}`, void 0, o),
61
+ exportSvg: async (id, o) => (await send("GET", `/boards/${seg(id)}/svg`, {}, o)).text(),
62
+ addShape: (id, shape, o) => json("POST", `/boards/${seg(id)}/shapes`, shape, o),
63
+ addConnector: (id, connector, o) => json("POST", `/boards/${seg(id)}/connectors`, connector, o),
64
+ drawFlow: (id, text, o) => json("POST", `/boards/${seg(id)}/flow`, { text }, o),
65
+ update: (id, element, patch, o) => json("PATCH", `/boards/${seg(id)}/elements/${seg(element)}`, patch, o),
66
+ move: (id, element, dx, dy, o) => json("POST", `/boards/${seg(id)}/move`, { element, dx, dy }, o),
67
+ remove: (id, element, o) => json("DELETE", `/boards/${seg(id)}/elements/${seg(element)}`, void 0, o),
68
+ uploadImage: async (data, o) => parse(await send("POST", "/images", { body: data, contentType: "application/octet-stream" }, o), o),
69
+ getImage: async (id, o) => {
70
+ const response = await send("GET", `/images/${seg(id)}`, {}, o);
71
+ return { bytes: await bytes(response), type: response.headers.get("content-type") ?? "application/octet-stream" };
72
+ },
73
+ state: async (id, o) => bytes(await send("GET", `/boards/${seg(id)}/state`, {}, o)),
74
+ checkpoint: async (id, update, o) => parse(await send("POST", `/boards/${seg(id)}/checkpoint`, { body: update, contentType: "application/octet-stream" }, o), o)
75
+ };
76
+ }
77
+ export {
78
+ CanvasApiError,
79
+ createClient
80
+ };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
- import { B as Board, P as Principal, a as BoardAccess } from './service-CJTe-uBI.js';
2
- export { b as BoardData, d as CanvasElement, e as CanvasError, c as CanvasService, C as Connector, D as DrawOptions, E as EdgeData, f as Endpoint, g as ErrorCode, F as FlowEdge, h as FlowGraph, i as FlowNode, G as Group, M as MAX_ELEMENTS, j as MAX_FLOW_EDGES, k as MAX_FLOW_NODES, l as MAX_TEXT, N as NodeData, m as Placement, n as SHAPE_TYPES, S as Shape, o as ShapeType, p as drawFlow, q as layoutFlow, r as parseFlow, s as principalSchema, t as readBoard } from './service-CJTe-uBI.js';
1
+ import { c as Board, P as Principal } from './read-Bdg1uiFC.js';
2
+ export { B as BoardData, d as CanvasElement, e as CanvasError, C as Connector, f as EdgeData, b as Endpoint, E as ErrorCode, G as Group, M as MAX_ELEMENTS, g as MAX_TEXT, N as NodeData, h as SHAPE_TYPES, a as Shape, S as ShapeType, p as principalSchema, r as readBoard } from './read-Bdg1uiFC.js';
3
+ import { B as BoardAccess } from './service-Cim7TWnJ.js';
4
+ export { C as CanvasService, D as DrawOptions, F as FlowEdge, a as FlowGraph, b as FlowNode, M as MAX_FLOW_EDGES, c as MAX_FLOW_NODES, P as Placement, d as drawFlow, l as layoutFlow, p as parseFlow } from './service-Cim7TWnJ.js';
3
5
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
4
6
  export { FileStoreOptions, createFileStore, openLocalStore } from './store-file.js';
5
7
  export { PRINCIPAL_KINDS, PrincipalKind, isMachineMade } from 'agentic-identity';
package/dist/index.js CHANGED
@@ -6,14 +6,14 @@ import {
6
6
  operatorActor,
7
7
  runMcp,
8
8
  svgToPng
9
- } from "./chunk-KEMOXKBY.js";
9
+ } from "./chunk-TSWXD4YG.js";
10
10
  import {
11
11
  createFileStore,
12
12
  openLocalStore
13
13
  } from "./chunk-UKST5A57.js";
14
14
  import {
15
15
  CanvasService
16
- } from "./chunk-W7NRP3EX.js";
16
+ } from "./chunk-J52RPFRP.js";
17
17
  import {
18
18
  Board,
19
19
  CanvasError,
@@ -30,7 +30,7 @@ import {
30
30
  principalSchema,
31
31
  readBoard,
32
32
  toSvg
33
- } from "./chunk-GGQPE65T.js";
33
+ } from "./chunk-JZA525X5.js";
34
34
  import "./chunk-NWQED42L.js";
35
35
  export {
36
36
  ActorConfigError,
@@ -5,9 +5,10 @@ import 'agentic-identity';
5
5
  import 'agentic-realtime';
6
6
  import 'agentic-identity/cloudflare';
7
7
  import 'hono';
8
- import './service-CJTe-uBI.js';
8
+ import './read-Bdg1uiFC.js';
9
9
  import 'yjs';
10
10
  import 'zod';
11
+ import './service-Cim7TWnJ.js';
11
12
 
12
13
  type Namespace = Parameters<typeof createDurableObjectRealtime>[0];
13
14
  interface LiveEnv extends WorkerEnv {
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  createApp
3
- } from "./chunk-V477KSZQ.js";
4
- import "./chunk-W7NRP3EX.js";
3
+ } from "./chunk-HPUYT5TC.js";
4
+ import "./chunk-J52RPFRP.js";
5
5
  import {
6
6
  CanvasError
7
- } from "./chunk-GGQPE65T.js";
7
+ } from "./chunk-JZA525X5.js";
8
8
  import "./chunk-NWQED42L.js";
9
9
 
10
10
  // src/live-worker.ts
package/dist/live.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { B as Board, P as Principal, a as BoardAccess, b as BoardData, S as Shape, C as Connector, D as DrawOptions } from './service-CJTe-uBI.js';
1
+ import { c as Board, P as Principal, B as BoardData, a as Shape, C as Connector, d as CanvasElement } from './read-Bdg1uiFC.js';
2
2
  import { Peer } from 'agentic-realtime/client';
3
+ import { B as BoardAccess, D as DrawOptions } from './service-Cim7TWnJ.js';
3
4
  import 'yjs';
4
5
  import 'zod';
5
6
  import 'agentic-identity';
@@ -78,12 +79,17 @@ declare class LiveService implements BoardAccess {
78
79
  id: string;
79
80
  title: string;
80
81
  }>;
82
+ list(): Promise<{
83
+ id: string;
84
+ title: string;
85
+ }[]>;
81
86
  read(id: string): Promise<BoardData & {
82
87
  id: string;
83
88
  }>;
84
89
  exportSvg(id: string): Promise<string>;
85
90
  add(id: string, shape: unknown, _actor?: Principal): Promise<Shape>;
86
91
  connect(id: string, connector: unknown, _actor?: Principal): Promise<Connector>;
92
+ update(id: string, element: string, patch: unknown, _actor?: Principal): Promise<CanvasElement>;
87
93
  move(id: string, element: string, dx: number, dy: number, _actor?: Principal): Promise<{
88
94
  moved: string[];
89
95
  }>;
package/dist/live.js CHANGED
@@ -5,11 +5,10 @@ import {
5
5
  principalSchema,
6
6
  readBoard,
7
7
  toSvg
8
- } from "./chunk-GGQPE65T.js";
8
+ } from "./chunk-JZA525X5.js";
9
9
 
10
10
  // src/live.ts
11
11
  import { SyncClient } from "agentic-realtime/client";
12
- import * as Y from "yjs";
13
12
  var CODES = ["INVALID", "DUPLICATE_ID", "NOT_FOUND", "BAD_REFERENCE", "LIMIT", "UNAVAILABLE", "FORBIDDEN"];
14
13
  var base = (server) => server.replace(/\/$/, "") + "/api/v1/canvas";
15
14
  async function refusal(response, fallback) {
@@ -61,7 +60,7 @@ var LiveBoard = class _LiveBoard {
61
60
  const id = encodeURIComponent(options.board);
62
61
  const stored = await call(options.server, options.token, `/boards/${id}/state`);
63
62
  if (!stored.ok) throw await refusal(stored, "could not read the stored board");
64
- const state = new Uint8Array(await stored.arrayBuffer());
63
+ await stored.body?.cancel();
65
64
  const url = new URL(`${base(options.server)}/boards/${id}/ws`);
66
65
  url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
67
66
  let client;
@@ -70,14 +69,6 @@ var LiveBoard = class _LiveBoard {
70
69
  } catch (error) {
71
70
  throw unreachable(error);
72
71
  }
73
- try {
74
- Y.applyUpdate(client.doc, state);
75
- await client.flush();
76
- if (me.role === "editor" && client.denied.length > 0) throw new CanvasError("FORBIDDEN", `the room refused the stored board: ${client.denied[0]}`);
77
- } catch (error) {
78
- await client.disconnect();
79
- throw unreachable(error);
80
- }
81
72
  return new _LiveBoard(new Board(client.doc), me, client, options.board, options, client.denied.length);
82
73
  }
83
74
  /** The other people and agents in the room. `machine` is true for an agent. */
@@ -142,6 +133,13 @@ var LiveService = class {
142
133
  if (typeof id !== "string" || typeof title !== "string") throw new CanvasError("INVALID", "the server sent a board this client does not know");
143
134
  return { id, title };
144
135
  }
136
+ async list() {
137
+ const response = await call(this.options.server, this.options.token, "/boards");
138
+ if (!response.ok) throw await refusal(response, "the server refused the request");
139
+ const { boards } = await json(response);
140
+ if (!Array.isArray(boards) || !boards.every((b) => typeof b?.id === "string" && typeof b?.title === "string")) throw new CanvasError("INVALID", "the server sent a board list this client does not know");
141
+ return boards;
142
+ }
145
143
  async read(id) {
146
144
  return this.use(id, async (live) => ({ id, ...readBoard(live.board) }));
147
145
  }
@@ -154,6 +152,9 @@ var LiveService = class {
154
152
  connect(id, connector, _actor) {
155
153
  return this.write(id, (board, actor) => board.addConnector(connector, actor));
156
154
  }
155
+ update(id, element, patch, _actor) {
156
+ return this.write(id, (board, actor) => board.update(element, patch, actor));
157
+ }
157
158
  move(id, element, dx, dy, _actor) {
158
159
  return this.write(id, (board, actor) => ({ moved: board.move(element, dx, dy, actor) }));
159
160
  }
@@ -1,6 +1,5 @@
1
1
  import * as Y from 'yjs';
2
2
  import { z } from 'zod';
3
- import { Store } from 'agentic-identity';
4
3
 
5
4
  declare const principalSchema: z.ZodObject<{
6
5
  kind: z.ZodEnum<["human", "agent_of_human", "agent_of_agent", "agent", "user_token"]>;
@@ -109,8 +108,17 @@ declare class Board {
109
108
  * author, and a changed one needs a trusted editor or it goes back to its prior state. An editor stamp changed alone
110
109
  * to an untrusted principal is put back. Unknown keys, nested Yjs types, and bad or foreign title values are deleted
111
110
  * or undone. Returns the ids it deleted or restored.
111
+ *
112
+ * `writer` says who sent the update that holds a Yjs item, or undefined when it does not know. Where it knows, it
113
+ * decides: a new element gets its creator as author and editor, and an old one gets the sender of its changes as editor.
114
+ * A client cannot claim another principal, and an agent cannot pass as a person. A new item that the log lacks has no
115
+ * sender: it is deleted or undone. Only an old item falls back to `trusted`. A hand save names its poster as the sender
116
+ * of every item that the room does not hold, in `writer`.
112
117
  */
113
- restamp(prior: Board, trusted: (who: Principal) => boolean): string[];
118
+ restamp(prior: Board, trusted: (who: Principal) => boolean, writer?: (item: {
119
+ client: number;
120
+ clock: number;
121
+ }) => Principal | undefined): string[];
114
122
  addShape(input: unknown, actor: Principal): Shape;
115
123
  addConnector(input: unknown, actor: Principal): Connector;
116
124
  update(elementId: string, patch: unknown, actor: Principal): CanvasElement;
@@ -143,52 +151,6 @@ declare class Board {
143
151
  private write;
144
152
  }
145
153
 
146
- declare const MAX_FLOW_NODES = 500;
147
- declare const MAX_FLOW_EDGES = 2000;
148
- interface FlowNode {
149
- id: string;
150
- text: string;
151
- shape: Extract<ShapeType, "rect" | "ellipse" | "diamond">;
152
- }
153
- interface FlowEdge {
154
- from: string;
155
- to: string;
156
- text: string;
157
- }
158
- interface FlowGraph {
159
- direction: "TB" | "LR";
160
- nodes: FlowNode[];
161
- edges: FlowEdge[];
162
- }
163
- declare function parseFlow(source: string): FlowGraph;
164
- interface Placement {
165
- id: string;
166
- x: number;
167
- y: number;
168
- w: number;
169
- h: number;
170
- }
171
- /** Layered layout. The top-left of the result is (0, 0). The layout breaks cycles and handles self-loops. */
172
- declare function layoutFlow(graph: FlowGraph): Placement[];
173
- interface DrawOptions {
174
- /**
175
- * Put in front of every id. Default: a new random prefix for each call, so two agents that draw at
176
- * the same time never write the same id. A prefix you pass is used as given, and it makes ids
177
- * repeatable. Up to 16 of A-Z, a-z, 0-9, _ and -.
178
- */
179
- idPrefix?: string;
180
- /** Top-left of the drawing. Default: below the shapes already on the board. */
181
- origin?: {
182
- x: number;
183
- y: number;
184
- };
185
- }
186
- /** Draw a flow on the board. All or nothing: on any error the board stays as it was. */
187
- declare function drawFlow(board: Board, source: string, actor: Principal, options?: DrawOptions): {
188
- nodes: string[];
189
- edges: string[];
190
- };
191
-
192
154
  interface Labels {
193
155
  /** The author is an agent or acts for one. */
194
156
  machineMade: boolean;
@@ -211,63 +173,4 @@ interface BoardData {
211
173
  /** The board as plain data for an agent. Reads only. Embedded image bytes are left out. */
212
174
  declare function readBoard(board: Board): BoardData;
213
175
 
214
- /** One place for every board operation. The CLI, the MCP server, and the Worker call it. */
215
- declare class CanvasService {
216
- private readonly store;
217
- constructor(store: Store);
218
- create(actor: Principal, options?: {
219
- id?: string;
220
- title?: string;
221
- }): Promise<{
222
- id: string;
223
- title: string;
224
- }>;
225
- /** Throws NOT_FOUND unless the board exists. A live room opens only for a board that exists. */
226
- assertExists(id: string): Promise<void>;
227
- read(id: string): Promise<BoardData & {
228
- id: string;
229
- }>;
230
- /** Run `change` on the board and save it, all inside one transaction. */
231
- change<R>(id: string, change: (board: Board) => R): Promise<R>;
232
- add(id: string, shape: unknown, actor: Principal): Promise<Shape>;
233
- connect(id: string, connector: unknown, actor: Principal): Promise<Connector>;
234
- move(id: string, elementId: string, dx: number, dy: number, actor: Principal): Promise<{
235
- moved: string[];
236
- }>;
237
- remove(id: string, elementId: string): Promise<{
238
- removed: string[];
239
- }>;
240
- flow(id: string, text: string, actor: Principal, options?: DrawOptions): Promise<{
241
- nodes: string[];
242
- edges: string[];
243
- }>;
244
- exportSvg(id: string): Promise<string>;
245
- /** The stored board as a Yjs update. A client applies it to a room to seed it: the room does not read it. */
246
- state(id: string): Promise<Uint8Array>;
247
- /**
248
- * Merge a live room's state into the stored board. `authors` are the principals the room saw send updates.
249
- * An element stamped by anyone else is deleted, and a changed author is put back (see `Board.restamp`),
250
- * so a client that writes raw Yjs cannot put another author on its work. Broken entries are repaired and
251
- * a board past the element cap is refused. Returns the ids the checks fixed.
252
- *
253
- * Limits: the save corrects the stored board only. The room keeps what its clients wrote, so a client that sees
254
- * a non-empty `fixed` must join again, or its later edits are lost at the next save. The room remembers its
255
- * authors for good, so a client may stamp an element with the name of anyone who once sent an update in that room.
256
- * A client that adds a root type of its own makes every later save of that room fail, because the room keeps it.
257
- */
258
- checkpoint(id: string, update: Uint8Array, actor: Principal, authors?: Principal[]): Promise<{
259
- elements: number;
260
- fixed: string[];
261
- }>;
262
- /** Owner only. Repair a board and delete the named elements. Only a human actor may call it. */
263
- repair(id: string, actor: Principal, drop?: string[]): Promise<{
264
- id: string;
265
- fixed: string[];
266
- elements: number;
267
- }>;
268
- private load;
269
- }
270
- /** What the CLI and the MCP server need. `CanvasService` runs it on a store, and `LiveService` runs it in a live room. */
271
- type BoardAccess = Pick<CanvasService, "create" | "read" | "add" | "connect" | "move" | "remove" | "flow" | "exportSvg">;
272
-
273
- export { Board as B, type Connector as C, type DrawOptions as D, type EdgeData as E, type FlowEdge as F, type Group as G, MAX_ELEMENTS as M, type NodeData as N, type Principal as P, type Shape as S, type BoardAccess as a, type BoardData as b, CanvasService as c, type CanvasElement as d, CanvasError as e, type Endpoint as f, type ErrorCode as g, type FlowGraph as h, type FlowNode as i, MAX_FLOW_EDGES as j, MAX_FLOW_NODES as k, MAX_TEXT as l, type Placement as m, SHAPE_TYPES as n, type ShapeType as o, drawFlow as p, layoutFlow as q, parseFlow as r, principalSchema as s, readBoard as t };
176
+ export { type BoardData as B, type Connector as C, type ErrorCode as E, type Group as G, MAX_ELEMENTS as M, type NodeData as N, type Principal as P, type ShapeType as S, type Shape as a, type Endpoint as b, Board as c, type CanvasElement as d, CanvasError as e, type EdgeData as f, MAX_TEXT as g, SHAPE_TYPES as h, principalSchema as p, readBoard as r };