From 4c356cd24c94c1a89a45d02359b0779f096ca32e Mon Sep 17 00:00:00 2001 From: elpresidank Date: Fri, 1 May 2026 22:16:28 -0500 Subject: [PATCH] fix(client): use correct put/delete config wire shape MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ConfigApi.putConfig and deleteConfig (and the duplicate in FlowsApi) sent a flat values:[{type,key,value}] array and a keys:{type,key} object — neither matches the ConfigService schema, which requires keys:[namespace, ...innerKeys] and values:Record. Every save in the workbench /mcp-tools page returned `Put requires at least one key (namespace)`. putConfig now groups items by type (namespace) and issues one put per group; deleteConfig sends keys:[type, key]. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../client/src/socket/trustgraph-socket.ts | 82 +++++++++++++------ 1 file changed, 56 insertions(+), 26 deletions(-) diff --git a/ts/packages/client/src/socket/trustgraph-socket.ts b/ts/packages/client/src/socket/trustgraph-socket.ts index 104ca57f..89a9f13e 100644 --- a/ts/packages/client/src/socket/trustgraph-socket.ts +++ b/ts/packages/client/src/socket/trustgraph-socket.ts @@ -1138,28 +1138,43 @@ export class FlowsApi { } /** - * Updates configuration values + * Updates configuration values. Items are grouped by `type` (the namespace); + * one put request is issued per distinct type. */ - putConfig(values: { type: string; key: string; value: string }[]) { - return this.api.makeRequest( - "config", - { - operation: "put", - values: values, - }, - 60000, - ); + putConfig(items: { type: string; key: string; value: string }[]) { + const byType = new Map>(); + for (const item of items) { + let group = byType.get(item.type); + if (!group) { + group = {}; + byType.set(item.type, group); + } + group[item.key] = item.value; + } + return Promise.all( + [...byType.entries()].map(([type, values]) => + this.api.makeRequest( + "config", + { + operation: "put", + keys: [type], + values, + }, + 60000, + ), + ), + ).then((responses) => responses[responses.length - 1]); } /** - * Deletes configuration entries + * Deletes a configuration entry */ - deleteConfig(keys: { type: string; key: string }) { + deleteConfig(target: { type: string; key: string }) { return this.api.makeRequest( "config", { operation: "delete", - keys: keys, + keys: [target.type, target.key], }, 30000, ); @@ -2031,28 +2046,43 @@ export class ConfigApi { } /** - * Updates configuration values + * Updates configuration values. Items are grouped by `type` (the namespace); + * one put request is issued per distinct type. */ - putConfig(values: { type: string; key: string; value: string }[]) { - return this.api.makeRequest( - "config", - { - operation: "put", - values: values, - }, - 60000, - ); + putConfig(items: { type: string; key: string; value: string }[]) { + const byType = new Map>(); + for (const item of items) { + let group = byType.get(item.type); + if (!group) { + group = {}; + byType.set(item.type, group); + } + group[item.key] = item.value; + } + return Promise.all( + [...byType.entries()].map(([type, values]) => + this.api.makeRequest( + "config", + { + operation: "put", + keys: [type], + values, + }, + 60000, + ), + ), + ).then((responses) => responses[responses.length - 1]); } /** - * Deletes configuration entries + * Deletes a configuration entry */ - deleteConfig(keys: { type: string; key: string }) { + deleteConfig(target: { type: string; key: string }) { return this.api.makeRequest( "config", { operation: "delete", - keys: keys, + keys: [target.type, target.key], }, 30000, );