pmx-canvas 0.1.32 → 0.1.33

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/CHANGELOG.md CHANGED
@@ -5,6 +5,26 @@ All notable changes to `pmx-canvas` are documented here. This project follows
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.1.33] - 2026-06-08
9
+
10
+ ### Changed
11
+
12
+ - **Edge creation echoes the full edge.** `POST /api/canvas/edge` now returns the
13
+ complete created edge — `from`, `to`, `type`, `style`, and `animated` alongside
14
+ `ok` and `id` — instead of just `{ ok, id }`. This mirrors how node creation
15
+ echoes the created node, so a client no longer has to re-read the layout to learn
16
+ the resolved edge shape. Additive on the HTTP response; the SDK `addEdge` still
17
+ returns the bare edge id.
18
+
19
+ ### Fixed
20
+
21
+ - **Bodyless and malformed JSON `POST`s are handled cleanly.** `readJson` now
22
+ reads the raw request body and treats an empty/whitespace body as `{}` without
23
+ logging a spurious warning (e.g. `POST /api/canvas/fit` with no body), and
24
+ rejects a top-level JSON array (or any non-object) to `{}` instead of letting it
25
+ flow through as though it were an object. Endpoints that read optional fields
26
+ from the body keep working with or without a payload.
27
+
8
28
  ## [0.1.32] - 2026-06-07
9
29
 
10
30
  ### Added
@@ -1690,6 +1710,7 @@ otherwise have to discover by trial and error.
1690
1710
  - Regression coverage for snapshot flat-`id` aliases on both MCP and
1691
1711
  HTTP surfaces, plus async / top-level-`await` WebView script bodies.
1692
1712
 
1713
+ [0.1.33]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.33
1693
1714
  [0.1.32]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.32
1694
1715
  [0.1.31]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.31
1695
1716
  [0.1.30]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.30
@@ -197,11 +197,7 @@ export declare function addCanvasEdge(input: {
197
197
  label?: string;
198
198
  style?: CanvasEdge['style'];
199
199
  animated?: boolean;
200
- }): {
201
- id: string;
202
- from: string;
203
- to: string;
204
- };
200
+ }): CanvasEdge;
205
201
  export declare function removeCanvasEdge(id: string): {
206
202
  removed: boolean;
207
203
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmx-canvas",
3
- "version": "0.1.32",
3
+ "version": "0.1.33",
4
4
  "description": "Spatial canvas workbench for coding agents — infinite 2D canvas with agent-native CLI, MCP integration, nodes, edges, file watching, and snapshots",
5
5
  "type": "module",
6
6
  "main": "./src/server/index.ts",
@@ -1363,7 +1363,7 @@ export function addCanvasEdge(input: {
1363
1363
  label?: string;
1364
1364
  style?: CanvasEdge['style'];
1365
1365
  animated?: boolean;
1366
- }): { id: string; from: string; to: string } {
1366
+ }): CanvasEdge {
1367
1367
  const fromResult = resolveCanvasNode({
1368
1368
  ...(typeof input.from === 'string' ? { id: input.from } : {}),
1369
1369
  ...(typeof input.fromSearch === 'string' ? { search: input.fromSearch } : {}),
@@ -1393,7 +1393,7 @@ export function addCanvasEdge(input: {
1393
1393
  if (!added) {
1394
1394
  throw new Error('Duplicate or self-edge.');
1395
1395
  }
1396
- return { id, from: fromResult.node.id, to: toResult.node.id };
1396
+ return edge;
1397
1397
  }
1398
1398
 
1399
1399
  export function removeCanvasEdge(id: string): { removed: boolean } {
@@ -1051,16 +1051,25 @@ function rotatePrimaryWorkbenchSessionIfNeeded(): void {
1051
1051
  primaryWorkbenchSessionId = `pmx-${Date.now().toString(36)}`;
1052
1052
  }
1053
1053
 
1054
- function readJson(req: Request): Promise<Record<string, unknown>> {
1055
- return req.json()
1056
- .then((value) => {
1057
- if (!value || typeof value !== 'object') return {};
1058
- return value as Record<string, unknown>;
1059
- })
1060
- .catch((error) => {
1061
- logWorkbenchWarning('readJson', error);
1062
- return {};
1063
- });
1054
+ async function readJson(req: Request): Promise<Record<string, unknown>> {
1055
+ let text = '';
1056
+ try {
1057
+ text = await req.text();
1058
+ } catch (error) {
1059
+ logWorkbenchWarning('readJson', error);
1060
+ return {};
1061
+ }
1062
+
1063
+ if (!text.trim()) return {};
1064
+
1065
+ try {
1066
+ const value = JSON.parse(text) as unknown;
1067
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return {};
1068
+ return value as Record<string, unknown>;
1069
+ } catch (error) {
1070
+ logWorkbenchWarning('readJson', error);
1071
+ return {};
1072
+ }
1064
1073
  }
1065
1074
 
1066
1075
  function htmlEscape(value: string): string {