refactor: set_module_example_data escribe via el server Python
La tool llamaba a `action_ws=setStaticVars`, que hace un file_put_contents del builder.json ENTERO en la web para cambiar una sola clave. Eso se saltaba las dos garantias que protegen ese fichero: el bloqueo de escritura de la API de ficheros (BLOCKED_GENERATED_FILENAMES en handlers/files.py) y la allowlist de /api/modules/update-metadata. El riesgo no era teorico. El builder.json es la unica memoria de que variable vive en que columna de builder_custom: si una compilacion caia entre la lectura y la escritura de setStaticVars, esta devolvia el mapeo var->columna anterior encima del recien generado y el contenido guardado quedaba colgado de la variable equivocada en TODAS las paginas que usan el modulo. Ahora delega en /api/modules/update-metadata, que ya es la via quirurgica para la metadata y acepta staticVars en su allowlist (objeto, <=64KB, <=200 claves). Se aprovecha para quitar el volcado del schema y del payload completos por consola en cada llamada. Companion en el repo de Forge: compiler.js reenvia staticVars en cada compilacion. Antes no lo mandaba, asi que el CMS lo tiraba al regenerar el builder.json — solo 5 de 4870 modulos lo conservaban. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,17 @@
|
||||
import { z } from "zod";
|
||||
import { withAuth, getSessionCredentials, getApiClient, getCommonParams } from "../../auth/index.js";
|
||||
import { handleToolError, validateRequired, handleApiResponse } from "../helpers/errorHandler.js";
|
||||
import { withAuth } from "../../auth/index.js";
|
||||
import { handleToolError, validateRequired } from "../helpers/errorHandler.js";
|
||||
import { withAuthParams } from "../helpers/authSchema.js";
|
||||
import { pythonPost } from "../helpers/pythonServerClient.js";
|
||||
import { getCurrentProjectInfo } from "../files/helpers.js";
|
||||
|
||||
// Antes esta tool llamaba a `action_ws=setStaticVars`, que hacia un
|
||||
// file_put_contents del builder.json ENTERO en la web para cambiar una sola
|
||||
// clave. Eso se saltaba el bloqueo de escritura de builder.json y, si caia una
|
||||
// compilacion entre su lectura y su escritura, devolvia el mapeo var->columna
|
||||
// anterior encima del recien generado (contenido rotado en todas las paginas
|
||||
// que usan el modulo). Ahora delega en el endpoint quirurgico de Forge, que
|
||||
// escribe SOLO las claves de su allowlist.
|
||||
|
||||
export function registerSetModuleExampleDataTool(server) {
|
||||
server.tool(
|
||||
@@ -50,42 +60,36 @@ Si dudas del formato exacto, lee 'read_doc({ name: "01-builder-fields" })'.`,
|
||||
}
|
||||
}
|
||||
|
||||
const credentials = await getSessionCredentials(extra.sessionId);
|
||||
const client = await getApiClient(extra.sessionId);
|
||||
console.error(`[set_module_example_data] Module ID: ${moduleId}, vars: ${Object.keys(exampleData).length}`);
|
||||
|
||||
// Log data for debugging
|
||||
console.error(`[set_module_example_data] Module ID: ${moduleId}`);
|
||||
console.error(`[set_module_example_data] Module Schema:`, JSON.stringify(moduleSchema, null, 2));
|
||||
console.error(`[set_module_example_data] Example Data:`, JSON.stringify(exampleData, null, 2));
|
||||
|
||||
// Prepare payload for setStaticVars action
|
||||
const payload = await getCommonParams(extra.sessionId, {
|
||||
action_ws: "setStaticVars",
|
||||
moduleId: moduleId,
|
||||
const { projectSlug } = getCurrentProjectInfo();
|
||||
const result = await pythonPost("/api/modules/update-metadata", {
|
||||
project: projectSlug,
|
||||
module: moduleId,
|
||||
staticVars: exampleData,
|
||||
schema: moduleSchema
|
||||
});
|
||||
|
||||
console.error(`[set_module_example_data] Full Payload:`, JSON.stringify(payload, null, 2));
|
||||
|
||||
// Send to viewer_functions
|
||||
const response = await client.post("/cms/lib/viewer_functions.php", payload);
|
||||
|
||||
console.error(`[set_module_example_data] Response:`, JSON.stringify(response.data, null, 2));
|
||||
|
||||
// Check for API errors in response
|
||||
const apiError = handleApiResponse(response.data, 'set_module_example_data');
|
||||
if (apiError) return apiError;
|
||||
if (!result?.success) {
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: JSON.stringify({
|
||||
success: false,
|
||||
error: result?.error || "Could not set module example data",
|
||||
}),
|
||||
}],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
content: [{
|
||||
type: "text", text: JSON.stringify({
|
||||
success: true,
|
||||
message: `Example data set successfully for module '${moduleId}'`,
|
||||
moduleId: moduleId,
|
||||
moduleId: result.module || moduleId,
|
||||
dataCount: Object.keys(exampleData).length,
|
||||
schemaVarsCount: moduleSchema?.codeVars ? Object.keys(moduleSchema.codeVars).length : 0,
|
||||
response: response.data
|
||||
}, null, 2)
|
||||
}],
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user