Initial commit

This commit is contained in:
Jordan
2026-04-01 23:16:45 +01:00
commit 91cfdaee72
200 changed files with 25589 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
import { z } from "zod";
import { withAuth, getSessionCredentials } from "../../auth/index.js";
import { handleToolError, validateRequired, handleApiResponse } from "../helpers/errorHandler.js";
import { AcaiHttpClient } from "../helpers/acaiHttpClient.js";
import { withAuthParams } from "../helpers/authSchema.js";
export function registerListTableRecordsTool(server) {
server.tool(
"list_table_records",
"List or search records in a database table. Returns JSON. Default limit is 50 — request only what you need. Use 'fields' to return only the columns you need (saves tokens). ALWAYS use 'num' as primary key, NEVER 'id'. Upload fields are arrays with urlPath.",
withAuthParams({
tableName: z.string().describe("Name of the table (without 'cms_' prefix, e.g., 'productos')"),
page: z.number().optional().describe("Page number (default: 1)"),
where: z.string().optional().describe("SQL WHERE clause to filter records (e.g., \"name LIKE '%keyword%'\")"),
limit: z.number().optional().describe("Max records to return. Default: 50. Use 5-10 for previews, up to 200 max for large exports."),
fields: z.array(z.string()).optional().describe("Return only these columns (e.g., ['num', 'titulo', 'precio']). Omit to return all columns. Always include 'num' if you need record IDs."),
truncateText: z.number().optional().describe("Truncate string field values longer than this many chars. Appends '... [truncated, N chars]'. Combine with 'fields' for maximum token savings."),
}),
{ readOnlyHint: true, destructiveHint: false },
withAuth(async ({ tableName, page, where, limit, fields, truncateText }, extra) => {
try {
// Validate required parameters
const validationError = validateRequired({ tableName }, ['tableName'], 'list_table_records');
if (validationError) return validationError;
// Build payload for CMS API
const credentials = await getSessionCredentials(extra.sessionId);
const payload = {
tableName: tableName,
where: where || "",
order: "",
limit: limit || 50,
options: {}
};
// Send to CMS API via viewer_functions
const response = await AcaiHttpClient.postCmsApi(
credentials,
'get',
payload,
credentials.token,
credentials.tokenHash
);
// Check for API errors
const apiError = handleApiResponse(response.data, 'list_table_records');
if (apiError) return apiError;
// Post-process: filter fields if requested
let resultData = response.data;
if (fields && fields.length > 0 && Array.isArray(resultData?.data)) {
resultData = {
...resultData,
data: resultData.data.map(record =>
Object.fromEntries(fields.map(f => [f, record[f]]))
)
};
}
// Post-process: truncate long text values if requested
if (truncateText && truncateText > 0 && Array.isArray(resultData?.data)) {
resultData = {
...resultData,
data: resultData.data.map(record => {
const truncated = {};
for (const [key, value] of Object.entries(record)) {
if (typeof value === 'string' && value.length > truncateText) {
truncated[key] = value.substring(0, truncateText) + `... [truncated, ${value.length} chars]`;
} else {
truncated[key] = value;
}
}
return truncated;
})
};
}
return {
content: [{
type: "text",
text: JSON.stringify(resultData, null, 2)
}],
};
} catch (error) {
return handleToolError(error, 'list_table_records', { tableName, page });
}
})
);
}