agentic-canvas 0.15.2 → 0.15.4
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 +9 -4
- package/dist/{chunk-PX6ZSCRO.js → chunk-YPGVHLV6.js} +1 -1
- package/dist/cli.js +1 -1
- package/dist/embed.js +12 -12
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -242,11 +242,17 @@ The static dev fallback holds no board roles. Its tokens reach every board and c
|
|
|
242
242
|
A host that runs a person's data export and erase imports `canvasAccount` from `agentic-canvas/account`. It never reads the storage layout.
|
|
243
243
|
|
|
244
244
|
```ts
|
|
245
|
+
import { createAccountRegistry } from "agentic-identity/account";
|
|
245
246
|
import { canvasAccount } from "agentic-canvas/account";
|
|
246
|
-
|
|
247
|
-
const
|
|
247
|
+
|
|
248
|
+
const registry = createAccountRegistry().register(canvasAccount, { store, saveRoom, eraseRoom });
|
|
249
|
+
const subject = { kind: "agent_of_human" as const, id: "assistant" };
|
|
250
|
+
const { zip, manifest } = await registry.export(subject);
|
|
251
|
+
const report = await registry.erase(subject, store, { actor: operator });
|
|
248
252
|
```
|
|
249
253
|
|
|
254
|
+
The host supplies `operator`, a `PrincipalContext` for the person or agent that runs the erase. Use `null` only for an anonymous or unattended erase.
|
|
255
|
+
|
|
250
256
|
Set `resourceType` (default `canvas`) and `collection` (default `boards`) to match the host. Board ids must still use 1 to 64 ASCII letters, digits, underscores, or hyphens, and must not start and end with two underscores. This rule also applies to custom resource types and external content sources. The output collection names stay the same. By default, rows without an `update` field are skipped. Give `isBoard(id, data)` to select rows by a host kind field. Rows of the configured resource type are always selected, so damaged personal data cannot be skipped. Selected rows that do not decode still fail with `INVALID`. Shared-board writes keep other row fields. Each scan reads the sharing resource for every stored row to check its type. An erase scans the collection, then reads stamped boards again inside transactions. Allow for these reads on large collections.
|
|
251
257
|
|
|
252
258
|
```ts
|
|
@@ -262,7 +268,7 @@ await canvasAccount.eraseAccount(subject, deps);
|
|
|
262
268
|
|
|
263
269
|
For content held outside the Store, give `contentSource: { exportContent(id), eraseContent(id) }`. Both methods return promises. The export method returns JSON; each sole-owned board exports as `{ id, content }`. Content must use arrays and plain objects from the current realm (with `Object.prototype` or a null prototype). The export rejects `undefined` values, functions, symbols, class instances, and non-finite numbers, including nested values. A `toJSON()` method can return supported JSON, so dates export as strings. The erase method deletes its content before sharing records go. This mode ignores `collection` and `isBoard`, does not read or write the content collection, and does not call `saveRoom` or `eraseRoom`. It uses sharing records to find sole-owned boards. It still exports and erases grants, invites, and audit data for the configured resource type. It does not inspect or scrub stamps in shared-board content: the host must handle that data separately. For a room backend, the methods can export room history and delete the room. Methods must tolerate retries, including missing content. A rejected method rejects the account call; earlier changes can remain. Sharing records for a failed content delete stay so a retry can finish. Stop writes during the operation.
|
|
264
270
|
|
|
265
|
-
The export
|
|
271
|
+
The registry puts each collection in a JSON file in the export zip. The direct contributor export returns plain JSON in the collections `boards`, `grants`, `invites`, `authored_elements`, `edited_elements`, `titles`, and `audit`. It has no format or time. The erase returns a count for each name.
|
|
266
272
|
|
|
267
273
|
- A board that the subject alone owns is deleted with its grants, invites, links, and audit entries. The erase calls `eraseRoom(boardId)` first, as the Worker does.
|
|
268
274
|
- On any other board, the subject's grant and invites go. The elements it made are deleted. A connector of someone else that was bound to one of them goes too, and no count or export lists it. The members of a deleted group move to its parent. The editor of an element it only edited becomes `(erased)`, and a title it set is cleared.
|
|
@@ -280,7 +286,6 @@ The export is plain JSON in the collections `boards`, `grants`, `invites`, `auth
|
|
|
280
286
|
- Image bytes in the image store have no uploader record, so they are not exported or erased. Only the `blob:` key in an element is.
|
|
281
287
|
- A deleted element leaves its id in the stored Yjs history. Its content is gone, and an id that the caller chose can stay in the stored bytes.
|
|
282
288
|
- A connector of someone else that the subject edited, and that goes with a deleted shape, is in `edited_elements` of the export and not in its erase count.
|
|
283
|
-
- The shape is provisional. It is the `AccountPackage` contract that a later `agentic-identity` release adds to `agentic-identity/account`. The `AccountApp` of 0.9.0 is a different contract, and this does not fit it.
|
|
284
289
|
|
|
285
290
|
## UI
|
|
286
291
|
|
package/dist/cli.js
CHANGED
package/dist/embed.js
CHANGED
|
@@ -11,7 +11,7 @@ import { Component } from "react";
|
|
|
11
11
|
import { createRoot } from "react-dom/client";
|
|
12
12
|
|
|
13
13
|
// ui/BoardView.tsx
|
|
14
|
-
import { Button as Button2, EmptyState, Input, PresenceChip, PresenceStack, Select, Textarea,
|
|
14
|
+
import { Button as Button2, EmptyState, IconButton, Input, PresenceChip, PresenceStack, Select, Textarea, useToast } from "agentic-design/react";
|
|
15
15
|
import { useCallback, useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState2 } from "react";
|
|
16
16
|
|
|
17
17
|
// ui/errors.ts
|
|
@@ -172,7 +172,7 @@ function Canvas({ data, selected, editable, view, onView, onSelect, onMove, onRe
|
|
|
172
172
|
/* @__PURE__ */ jsx("rect", { x, y: y - 20, width: el.machineMade ? 50 : 82, height: 18, rx: 4 }),
|
|
173
173
|
/* @__PURE__ */ jsx("text", { x: x + 6, y: y - 7, children: el.machineMade ? "Agent" : "Agent edit" })
|
|
174
174
|
] }) : null;
|
|
175
|
-
return /* @__PURE__ */ jsx("div", { ref: box, className: "canvas", role: "group", "aria-label": "Board canvas. Tab moves between items. Arrow keys move the selected item, Shift with arrows resizes it, Delete removes it, Escape clears the selection.", tabIndex:
|
|
175
|
+
return /* @__PURE__ */ jsx("div", { ref: box, className: "canvas", role: "group", "aria-label": "Board canvas. Tab moves between items. Arrow keys move the selected item, Shift with arrows resizes it, Delete removes it, Escape clears the selection.", tabIndex: -1, onKeyDown: key, onPointerMove: track, onPointerUp: end, onPointerCancel: end, children: /* @__PURE__ */ jsxs("svg", { width: "100%", height: "100%", onPointerDown: (e) => begin(e, "pan"), children: [
|
|
176
176
|
/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("marker", { id: "arrow", viewBox: "0 0 10 10", refX: "9", refY: "5", markerWidth: "8", markerHeight: "8", orient: "auto-start-reverse", children: /* @__PURE__ */ jsx("path", { d: "M0 0L10 5L0 10z", className: "arrowhead" }) }) }),
|
|
177
177
|
/* @__PURE__ */ jsxs("g", { transform: `translate(${view.x} ${view.y}) scale(${view.k})`, children: [
|
|
178
178
|
data.edges.map((e) => {
|
|
@@ -486,16 +486,16 @@ function BoardView({ id, client: remote, host, room: roomOptions, me, backHref }
|
|
|
486
486
|
!editable && /* @__PURE__ */ jsx3("p", { className: "note", children: host ? "This board is read only." : "This token can read the board but not change it." }),
|
|
487
487
|
/* @__PURE__ */ jsxs3("div", { className: "stage", children: [
|
|
488
488
|
/* @__PURE__ */ jsxs3("div", { className: "surface", ref: canvasBox, children: [
|
|
489
|
-
/* @__PURE__ */ jsx3("div", { className: "palette", children: /* @__PURE__ */ jsx3(
|
|
490
|
-
/* @__PURE__ */ jsx3("div", { className: "zoom", children: /* @__PURE__ */ jsxs3(
|
|
491
|
-
/* @__PURE__ */ jsx3(
|
|
492
|
-
/* @__PURE__ */ jsx3(
|
|
493
|
-
/* @__PURE__ */ jsx3(
|
|
494
|
-
/* @__PURE__ */ jsx3(
|
|
495
|
-
/* @__PURE__ */ jsx3(
|
|
496
|
-
/* @__PURE__ */ jsx3(
|
|
497
|
-
/* @__PURE__ */ jsx3(
|
|
498
|
-
/* @__PURE__ */ jsx3(
|
|
489
|
+
/* @__PURE__ */ jsx3("div", { className: "palette", children: /* @__PURE__ */ jsx3("div", { className: "agd-toolbar", role: "group", "aria-label": "Shape palette", children: TOOLS.map((t) => /* @__PURE__ */ jsx3(IconButton, { size: "sm", label: t.text, icon: t.icon, disabled: !editable, onClick: () => add(t.type) }, t.type)) }) }),
|
|
490
|
+
/* @__PURE__ */ jsx3("div", { className: "zoom", children: /* @__PURE__ */ jsxs3("div", { className: "agd-toolbar", role: "group", "aria-label": "Zoom and pan", children: [
|
|
491
|
+
/* @__PURE__ */ jsx3(IconButton, { size: "sm", label: "Zoom out", icon: icon(/* @__PURE__ */ jsx3("path", { d: "M4 10h12" })), onClick: () => zoom(1 / 1.25) }),
|
|
492
|
+
/* @__PURE__ */ jsx3(IconButton, { size: "sm", label: "Zoom in", icon: icon(/* @__PURE__ */ jsx3("path", { d: "M4 10h12M10 4v12" })), onClick: () => zoom(1.25) }),
|
|
493
|
+
/* @__PURE__ */ jsx3("span", { className: "agd-toolbar__separator", "aria-hidden": "true" }),
|
|
494
|
+
/* @__PURE__ */ jsx3(IconButton, { size: "sm", label: "Pan left", icon: icon(/* @__PURE__ */ jsx3("path", { d: "M12 4l-6 6 6 6" })), onClick: () => setView((v) => ({ ...v, x: v.x + PAN_STEP })) }),
|
|
495
|
+
/* @__PURE__ */ jsx3(IconButton, { size: "sm", label: "Pan right", icon: icon(/* @__PURE__ */ jsx3("path", { d: "M8 4l6 6-6 6" })), onClick: () => setView((v) => ({ ...v, x: v.x - PAN_STEP })) }),
|
|
496
|
+
/* @__PURE__ */ jsx3(IconButton, { size: "sm", label: "Pan up", icon: icon(/* @__PURE__ */ jsx3("path", { d: "M4 12l6-6 6 6" })), onClick: () => setView((v) => ({ ...v, y: v.y + PAN_STEP })) }),
|
|
497
|
+
/* @__PURE__ */ jsx3(IconButton, { size: "sm", label: "Pan down", icon: icon(/* @__PURE__ */ jsx3("path", { d: "M4 8l6 6 6-6" })), onClick: () => setView((v) => ({ ...v, y: v.y - PAN_STEP })) }),
|
|
498
|
+
/* @__PURE__ */ jsx3(IconButton, { size: "sm", label: "Reset view", icon: icon(/* @__PURE__ */ jsx3("path", { d: "M4 4h5M4 4v5M16 16h-5M16 16v-5" })), onClick: () => setView(HOME) })
|
|
499
499
|
] }) }),
|
|
500
500
|
/* @__PURE__ */ jsx3(Canvas, { data: d, selected, editable, view, onView: setView, onSelect: setSelected, onMove: move, onResize: resize, onDelete: remove }),
|
|
501
501
|
empty && /* @__PURE__ */ jsx3("div", { className: "empty-overlay", children: /* @__PURE__ */ jsx3(EmptyState, { title: "This board is empty", description: editable ? "Pick a shape from the palette to start." : "Nothing has been drawn yet." }) })
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentic-canvas",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.4",
|
|
4
4
|
"description": "A shared whiteboard for diagrams, drawn by people and agents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"whiteboard",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"clean": "rm -rf dist",
|
|
81
81
|
"dev": "npm run build && WRANGLER_SEND_METRICS=false wrangler dev --port 8793 --var CANVAS_REGION:unknown",
|
|
82
82
|
"dev:smoke": "npm run build && node scripts/dev-smoke.mjs 8793 /health --var CANVAS_REGION:unknown",
|
|
83
|
-
"ci:local": "npm run build && npm run typecheck && npm test && npm run test:e2e",
|
|
83
|
+
"ci:local": "npm run build && npm run typecheck && npm test && npm run test:e2e && node scripts/test-packed-account.mjs",
|
|
84
84
|
"deploy:demo": "wrangler deploy -c wrangler.demo.jsonc",
|
|
85
85
|
"test:e2e": "playwright test -c e2e/playwright.config.ts"
|
|
86
86
|
},
|