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/README.md +120 -10
- package/dist/{chunk-V477KSZQ.js → chunk-HPUYT5TC.js} +183 -8
- package/dist/{chunk-W7NRP3EX.js → chunk-J52RPFRP.js} +39 -8
- package/dist/{chunk-GGQPE65T.js → chunk-JZA525X5.js} +61 -2
- package/dist/{chunk-KEMOXKBY.js → chunk-TSWXD4YG.js} +15 -2
- package/dist/cli.js +13 -3
- package/dist/client.d.ts +119 -0
- package/dist/client.js +80 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +3 -3
- package/dist/live-worker.d.ts +2 -1
- package/dist/live-worker.js +3 -3
- package/dist/live.d.ts +7 -1
- package/dist/live.js +12 -11
- package/dist/{service-CJTe-uBI.d.ts → read-Bdg1uiFC.d.ts} +11 -108
- package/dist/service-Cim7TWnJ.d.ts +128 -0
- package/dist/worker.d.ts +5 -2
- package/dist/worker.js +5 -3
- package/llms.txt +3 -1
- package/package.json +21 -6
package/dist/cli.js
CHANGED
|
@@ -5,16 +5,16 @@ import {
|
|
|
5
5
|
operatorActor,
|
|
6
6
|
runMcp,
|
|
7
7
|
svgToPng
|
|
8
|
-
} from "./chunk-
|
|
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-
|
|
14
|
+
} from "./chunk-J52RPFRP.js";
|
|
15
15
|
import {
|
|
16
16
|
CanvasError
|
|
17
|
-
} from "./chunk-
|
|
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()));
|
package/dist/client.d.ts
ADDED
|
@@ -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 {
|
|
2
|
-
export {
|
|
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-
|
|
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-
|
|
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-
|
|
33
|
+
} from "./chunk-JZA525X5.js";
|
|
34
34
|
import "./chunk-NWQED42L.js";
|
|
35
35
|
export {
|
|
36
36
|
ActorConfigError,
|
package/dist/live-worker.d.ts
CHANGED
|
@@ -5,9 +5,10 @@ import 'agentic-identity';
|
|
|
5
5
|
import 'agentic-realtime';
|
|
6
6
|
import 'agentic-identity/cloudflare';
|
|
7
7
|
import 'hono';
|
|
8
|
-
import './
|
|
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 {
|
package/dist/live-worker.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createApp
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-HPUYT5TC.js";
|
|
4
|
+
import "./chunk-J52RPFRP.js";
|
|
5
5
|
import {
|
|
6
6
|
CanvasError
|
|
7
|
-
} from "./chunk-
|
|
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 {
|
|
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-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 };
|