@seatable/mcp-seatable 0.9.5
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/.env.example +11 -0
- package/LICENSE +21 -0
- package/README.md +302 -0
- package/bin/seatable-mcp.cjs +20 -0
- package/dist/auth/tokenValidator.d.ts +10 -0
- package/dist/auth/tokenValidator.d.ts.map +1 -0
- package/dist/auth/tokenValidator.js +55 -0
- package/dist/auth/tokenValidator.js.map +1 -0
- package/dist/config/env.d.ts +67 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +105 -0
- package/dist/config/env.js.map +1 -0
- package/dist/errors.d.ts +8 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +28 -0
- package/dist/errors.js.map +1 -0
- package/dist/http/httpServer.d.ts +7 -0
- package/dist/http/httpServer.d.ts.map +1 -0
- package/dist/http/httpServer.js +211 -0
- package/dist/http/httpServer.js.map +1 -0
- package/dist/http/sseServer.d.ts +11 -0
- package/dist/http/sseServer.d.ts.map +1 -0
- package/dist/http/sseServer.js +154 -0
- package/dist/http/sseServer.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +86 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +5 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +34 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp/server.d.ts +52 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +222 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/addRow.d.ts +3 -0
- package/dist/mcp/tools/addRow.d.ts.map +1 -0
- package/dist/mcp/tools/addRow.js +23 -0
- package/dist/mcp/tools/addRow.js.map +1 -0
- package/dist/mcp/tools/addSelectOption.d.ts +3 -0
- package/dist/mcp/tools/addSelectOption.d.ts.map +1 -0
- package/dist/mcp/tools/addSelectOption.js +27 -0
- package/dist/mcp/tools/addSelectOption.js.map +1 -0
- package/dist/mcp/tools/appendRows.d.ts +3 -0
- package/dist/mcp/tools/appendRows.d.ts.map +1 -0
- package/dist/mcp/tools/appendRows.js +27 -0
- package/dist/mcp/tools/appendRows.js.map +1 -0
- package/dist/mcp/tools/attachFileToRow.d.ts +3 -0
- package/dist/mcp/tools/attachFileToRow.d.ts.map +1 -0
- package/dist/mcp/tools/attachFileToRow.js +42 -0
- package/dist/mcp/tools/attachFileToRow.js.map +1 -0
- package/dist/mcp/tools/bulkSetSelectOptions.d.ts +3 -0
- package/dist/mcp/tools/bulkSetSelectOptions.d.ts.map +1 -0
- package/dist/mcp/tools/bulkSetSelectOptions.js +49 -0
- package/dist/mcp/tools/bulkSetSelectOptions.js.map +1 -0
- package/dist/mcp/tools/deleteRow.d.ts +3 -0
- package/dist/mcp/tools/deleteRow.d.ts.map +1 -0
- package/dist/mcp/tools/deleteRow.js +22 -0
- package/dist/mcp/tools/deleteRow.js.map +1 -0
- package/dist/mcp/tools/echoArgs.d.ts +3 -0
- package/dist/mcp/tools/echoArgs.d.ts.map +1 -0
- package/dist/mcp/tools/echoArgs.js +14 -0
- package/dist/mcp/tools/echoArgs.js.map +1 -0
- package/dist/mcp/tools/findRows.d.ts +9 -0
- package/dist/mcp/tools/findRows.d.ts.map +1 -0
- package/dist/mcp/tools/findRows.js +255 -0
- package/dist/mcp/tools/findRows.js.map +1 -0
- package/dist/mcp/tools/getRow.d.ts +3 -0
- package/dist/mcp/tools/getRow.d.ts.map +1 -0
- package/dist/mcp/tools/getRow.js +18 -0
- package/dist/mcp/tools/getRow.js.map +1 -0
- package/dist/mcp/tools/getSchema.d.ts +3 -0
- package/dist/mcp/tools/getSchema.d.ts.map +1 -0
- package/dist/mcp/tools/getSchema.js +16 -0
- package/dist/mcp/tools/getSchema.js.map +1 -0
- package/dist/mcp/tools/linkRows.d.ts +3 -0
- package/dist/mcp/tools/linkRows.d.ts.map +1 -0
- package/dist/mcp/tools/linkRows.js +23 -0
- package/dist/mcp/tools/linkRows.js.map +1 -0
- package/dist/mcp/tools/listBases.d.ts +3 -0
- package/dist/mcp/tools/listBases.d.ts.map +1 -0
- package/dist/mcp/tools/listBases.js +16 -0
- package/dist/mcp/tools/listBases.js.map +1 -0
- package/dist/mcp/tools/listCollaborators.d.ts +3 -0
- package/dist/mcp/tools/listCollaborators.d.ts.map +1 -0
- package/dist/mcp/tools/listCollaborators.js +16 -0
- package/dist/mcp/tools/listCollaborators.js.map +1 -0
- package/dist/mcp/tools/listRows.d.ts +3 -0
- package/dist/mcp/tools/listRows.d.ts.map +1 -0
- package/dist/mcp/tools/listRows.js +20 -0
- package/dist/mcp/tools/listRows.js.map +1 -0
- package/dist/mcp/tools/listTables.d.ts +3 -0
- package/dist/mcp/tools/listTables.d.ts.map +1 -0
- package/dist/mcp/tools/listTables.js +19 -0
- package/dist/mcp/tools/listTables.js.map +1 -0
- package/dist/mcp/tools/manageColumns.d.ts +3 -0
- package/dist/mcp/tools/manageColumns.d.ts.map +1 -0
- package/dist/mcp/tools/manageColumns.js +44 -0
- package/dist/mcp/tools/manageColumns.js.map +1 -0
- package/dist/mcp/tools/manageTables.d.ts +3 -0
- package/dist/mcp/tools/manageTables.d.ts.map +1 -0
- package/dist/mcp/tools/manageTables.js +36 -0
- package/dist/mcp/tools/manageTables.js.map +1 -0
- package/dist/mcp/tools/pingSeatable.d.ts +3 -0
- package/dist/mcp/tools/pingSeatable.d.ts.map +1 -0
- package/dist/mcp/tools/pingSeatable.js +37 -0
- package/dist/mcp/tools/pingSeatable.js.map +1 -0
- package/dist/mcp/tools/querySql.d.ts +3 -0
- package/dist/mcp/tools/querySql.d.ts.map +1 -0
- package/dist/mcp/tools/querySql.js +28 -0
- package/dist/mcp/tools/querySql.js.map +1 -0
- package/dist/mcp/tools/searchRows.d.ts +3 -0
- package/dist/mcp/tools/searchRows.d.ts.map +1 -0
- package/dist/mcp/tools/searchRows.js +18 -0
- package/dist/mcp/tools/searchRows.js.map +1 -0
- package/dist/mcp/tools/types.d.ts +90 -0
- package/dist/mcp/tools/types.d.ts.map +1 -0
- package/dist/mcp/tools/types.js +2 -0
- package/dist/mcp/tools/types.js.map +1 -0
- package/dist/mcp/tools/unlinkRows.d.ts +3 -0
- package/dist/mcp/tools/unlinkRows.d.ts.map +1 -0
- package/dist/mcp/tools/unlinkRows.js +23 -0
- package/dist/mcp/tools/unlinkRows.js.map +1 -0
- package/dist/mcp/tools/updateRow.d.ts +3 -0
- package/dist/mcp/tools/updateRow.d.ts.map +1 -0
- package/dist/mcp/tools/updateRow.js +32 -0
- package/dist/mcp/tools/updateRow.js.map +1 -0
- package/dist/mcp/tools/uploadFile.d.ts +3 -0
- package/dist/mcp/tools/uploadFile.d.ts.map +1 -0
- package/dist/mcp/tools/uploadFile.js +29 -0
- package/dist/mcp/tools/uploadFile.js.map +1 -0
- package/dist/mcp/tools/upsertRows.d.ts +3 -0
- package/dist/mcp/tools/upsertRows.d.ts.map +1 -0
- package/dist/mcp/tools/upsertRows.js +55 -0
- package/dist/mcp/tools/upsertRows.js.map +1 -0
- package/dist/ratelimit/connectionCounter.d.ts +11 -0
- package/dist/ratelimit/connectionCounter.d.ts.map +1 -0
- package/dist/ratelimit/connectionCounter.js +27 -0
- package/dist/ratelimit/connectionCounter.js.map +1 -0
- package/dist/ratelimit/index.d.ts +27 -0
- package/dist/ratelimit/index.d.ts.map +1 -0
- package/dist/ratelimit/index.js +50 -0
- package/dist/ratelimit/index.js.map +1 -0
- package/dist/ratelimit/rateLimiter.d.ts +18 -0
- package/dist/ratelimit/rateLimiter.d.ts.map +1 -0
- package/dist/ratelimit/rateLimiter.js +54 -0
- package/dist/ratelimit/rateLimiter.js.map +1 -0
- package/dist/schema/generic.d.ts +126 -0
- package/dist/schema/generic.d.ts.map +1 -0
- package/dist/schema/generic.js +45 -0
- package/dist/schema/generic.js.map +1 -0
- package/dist/schema/jsonSchemaToZod.d.ts +3 -0
- package/dist/schema/jsonSchemaToZod.d.ts.map +1 -0
- package/dist/schema/jsonSchemaToZod.js +53 -0
- package/dist/schema/jsonSchemaToZod.js.map +1 -0
- package/dist/schema/map.d.ts +3 -0
- package/dist/schema/map.d.ts.map +1 -0
- package/dist/schema/map.js +92 -0
- package/dist/schema/map.js.map +1 -0
- package/dist/schema/validate.d.ts +15 -0
- package/dist/schema/validate.d.ts.map +1 -0
- package/dist/schema/validate.js +170 -0
- package/dist/schema/validate.js.map +1 -0
- package/dist/seatable/client.d.ts +106 -0
- package/dist/seatable/client.d.ts.map +1 -0
- package/dist/seatable/client.js +378 -0
- package/dist/seatable/client.js.map +1 -0
- package/dist/seatable/clientRegistry.d.ts +11 -0
- package/dist/seatable/clientRegistry.d.ts.map +1 -0
- package/dist/seatable/clientRegistry.js +33 -0
- package/dist/seatable/clientRegistry.js.map +1 -0
- package/dist/seatable/contextualClient.d.ts +92 -0
- package/dist/seatable/contextualClient.d.ts.map +1 -0
- package/dist/seatable/contextualClient.js +42 -0
- package/dist/seatable/contextualClient.js.map +1 -0
- package/dist/seatable/mockClient.d.ts +68 -0
- package/dist/seatable/mockClient.d.ts.map +1 -0
- package/dist/seatable/mockClient.js +115 -0
- package/dist/seatable/mockClient.js.map +1 -0
- package/dist/seatable/tokenManager.d.ts +28 -0
- package/dist/seatable/tokenManager.d.ts.map +1 -0
- package/dist/seatable/tokenManager.js +92 -0
- package/dist/seatable/tokenManager.js.map +1 -0
- package/dist/seatable/types.d.ts +22 -0
- package/dist/seatable/types.d.ts.map +1 -0
- package/dist/seatable/types.js +3 -0
- package/dist/seatable/types.js.map +1 -0
- package/dist/seatable/utils.d.ts +7 -0
- package/dist/seatable/utils.d.ts.map +1 -0
- package/dist/seatable/utils.js +25 -0
- package/dist/seatable/utils.js.map +1 -0
- package/package.json +94 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manageTables.js","sourceRoot":"","sources":["../../../src/mcp/tools/manageTables.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7B,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC9C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE;CAC7D,CAAC,CAAA;AAEF,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IACzB,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;CAC9C,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAkB,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,EAAE;IACtF,MAAM,CAAC,YAAY,CACf,eAAe,EACf;QACI,KAAK,EAAE,eAAe;QACtB,WAAW,EAAE,oCAAoC;QACjD,WAAW,EAAE,cAAc,CAAC,WAAW,CAAC;KAC3C,EACD,KAAK,EAAE,IAAa,EAAE,EAAE;QACpB,MAAM,EAAE,UAAU,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC9C,MAAM,OAAO,GAAG,EAAE,CAAA;QAClB,KAAK,MAAM,EAAE,IAAI,UAAU,EAAE,CAAC;YAC1B,IAAI,EAAE,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;gBACzB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,CAAA;gBACzD,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;YAClE,CAAC;iBAAM,IAAI,EAAE,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;gBAChC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,QAAS,CAAC,CAAA;gBAC3D,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;YACnF,CAAC;iBAAM,IAAI,EAAE,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;gBAChC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,CAAA;gBAC7C,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;YAClE,CAAC;QACL,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAA;IAC7E,CAAC,CACJ,CAAA;AACL,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pingSeatable.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/pingSeatable.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAI1C,eAAO,MAAM,oBAAoB,EAAE,aAoClC,CAAA"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const InputSchema = z.object({});
|
|
3
|
+
export const registerPingSeatable = (server, { client, getInputSchema }) => {
|
|
4
|
+
server.registerTool('ping_seatable', {
|
|
5
|
+
title: 'Ping SeaTable',
|
|
6
|
+
description: 'Health check that verifies connectivity and auth to SeaTable',
|
|
7
|
+
inputSchema: getInputSchema(InputSchema),
|
|
8
|
+
annotations: { readOnlyHint: true },
|
|
9
|
+
}, async () => {
|
|
10
|
+
const started = Date.now();
|
|
11
|
+
try {
|
|
12
|
+
// Prefer metadata endpoint for compatibility
|
|
13
|
+
await client.getMetadata();
|
|
14
|
+
const latencyMs = Date.now() - started;
|
|
15
|
+
return {
|
|
16
|
+
content: [
|
|
17
|
+
{
|
|
18
|
+
type: 'text',
|
|
19
|
+
text: JSON.stringify({ ok: true, latency_ms: latencyMs })
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
const latencyMs = Date.now() - started;
|
|
26
|
+
return {
|
|
27
|
+
content: [
|
|
28
|
+
{
|
|
29
|
+
type: 'text',
|
|
30
|
+
text: JSON.stringify({ ok: false, latency_ms: latencyMs, error: err.message })
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=pingSeatable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pingSeatable.js","sourceRoot":"","sources":["../../../src/mcp/tools/pingSeatable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;AAEhC,MAAM,CAAC,MAAM,oBAAoB,GAAkB,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,EAAE;IACtF,MAAM,CAAC,YAAY,CACf,eAAe,EACf;QACI,KAAK,EAAE,eAAe;QACtB,WAAW,EAAE,8DAA8D;QAC3E,WAAW,EAAE,cAAc,CAAC,WAAW,CAAC;QACxC,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;KACtC,EACD,KAAK,IAAI,EAAE;QACP,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QAC1B,IAAI,CAAC;YACD,6CAA6C;YAC7C,MAAM,MAAM,CAAC,WAAW,EAAE,CAAA;YAC1B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAA;YACtC,OAAO;gBACH,OAAO,EAAE;oBACL;wBACI,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;qBAC5D;iBACJ;aACJ,CAAA;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAA;YACtC,OAAO;gBACH,OAAO,EAAE;oBACL;wBACI,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAG,GAAa,CAAC,OAAO,EAAE,CAAC;qBAC5F;iBACJ;aACJ,CAAA;QACL,CAAC;IACL,CAAC,CACJ,CAAA;AACL,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"querySql.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/querySql.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAO1C,eAAO,MAAM,gBAAgB,EAAE,aAyB9B,CAAA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const InputSchema = z.object({
|
|
3
|
+
sql: z.string().describe('SQL query (SELECT, INSERT, UPDATE, DELETE)').refine(sql => sql.trim().length > 0, 'SQL query cannot be empty'),
|
|
4
|
+
parameters: z.array(z.union([z.string(), z.number(), z.boolean(), z.null()])).optional().describe('Values for ? placeholders in the SQL query'),
|
|
5
|
+
});
|
|
6
|
+
export const registerQuerySql = (server, { client, getInputSchema }) => {
|
|
7
|
+
server.registerTool('query_sql', {
|
|
8
|
+
title: 'Query SQL',
|
|
9
|
+
description: 'Execute raw SQL queries against SeaTable. Supports SELECT, INSERT, UPDATE, DELETE. Use ? placeholders for parameters to prevent SQL injection.',
|
|
10
|
+
inputSchema: getInputSchema(InputSchema),
|
|
11
|
+
annotations: { readOnlyHint: false },
|
|
12
|
+
}, async (args) => {
|
|
13
|
+
const { sql, parameters } = InputSchema.parse(args);
|
|
14
|
+
const result = await client.querySql(sql, parameters);
|
|
15
|
+
return {
|
|
16
|
+
content: [{
|
|
17
|
+
type: 'text',
|
|
18
|
+
text: JSON.stringify({
|
|
19
|
+
metadata: result.metadata,
|
|
20
|
+
results: result.results,
|
|
21
|
+
query: sql,
|
|
22
|
+
parameters: parameters || [],
|
|
23
|
+
}),
|
|
24
|
+
}],
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=querySql.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"querySql.js","sourceRoot":"","sources":["../../../src/mcp/tools/querySql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IACzB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,2BAA2B,CAAC;IACxI,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC;CAClJ,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAkB,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,EAAE;IAClF,MAAM,CAAC,YAAY,CACf,WAAW,EACX;QACI,KAAK,EAAE,WAAW;QAClB,WAAW,EAAE,gJAAgJ;QAC7J,WAAW,EAAE,cAAc,CAAC,WAAW,CAAC;QACxC,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE;KACvC,EACD,KAAK,EAAE,IAAa,EAAE,EAAE;QACpB,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACnD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC,CAAA;QACrD,OAAO;YACH,OAAO,EAAE,CAAC;oBACN,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;wBACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;wBACzB,OAAO,EAAE,MAAM,CAAC,OAAO;wBACvB,KAAK,EAAE,GAAG;wBACV,UAAU,EAAE,UAAU,IAAI,EAAE;qBAC/B,CAAC;iBACL,CAAC;SACL,CAAA;IACL,CAAC,CACJ,CAAA;AACL,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"searchRows.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/searchRows.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAO1C,eAAO,MAAM,kBAAkB,EAAE,aAehC,CAAA"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const InputSchema = z.object({
|
|
3
|
+
table: z.string().describe('Target table name'),
|
|
4
|
+
query: z.record(z.any()).describe('Filter object with column name -> value pairs'),
|
|
5
|
+
});
|
|
6
|
+
export const registerSearchRows = (server, { client, getInputSchema }) => {
|
|
7
|
+
server.registerTool('search_rows', {
|
|
8
|
+
title: 'Search Rows',
|
|
9
|
+
description: 'Search rows with a filter object',
|
|
10
|
+
inputSchema: getInputSchema(InputSchema),
|
|
11
|
+
annotations: { readOnlyHint: true },
|
|
12
|
+
}, async (args) => {
|
|
13
|
+
const parsed = InputSchema.parse(args);
|
|
14
|
+
const res = await client.searchRows(parsed.table, parsed.query);
|
|
15
|
+
return { content: [{ type: 'text', text: JSON.stringify(res) }] };
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=searchRows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"searchRows.js","sourceRoot":"","sources":["../../../src/mcp/tools/searchRows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IACzB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC;IAC/C,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,+CAA+C,CAAC;CACrF,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAkB,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,EAAE;IACpF,MAAM,CAAC,YAAY,CACf,aAAa,EACb;QACI,KAAK,EAAE,aAAa;QACpB,WAAW,EAAE,kCAAkC;QAC/C,WAAW,EAAE,cAAc,CAAC,WAAW,CAAC;QACxC,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;KACtC,EACD,KAAK,EAAE,IAAa,EAAE,EAAE;QACpB,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACtC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;QAC/D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAA;IACrE,CAAC,CACJ,CAAA;AACL,CAAC,CAAA"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
export type McpServerLike = {
|
|
2
|
+
registerTool: (...args: any[]) => any;
|
|
3
|
+
};
|
|
4
|
+
import type { Env } from '../../config/env.js';
|
|
5
|
+
export interface ClientLike {
|
|
6
|
+
listTables(): Promise<Array<{
|
|
7
|
+
name: string;
|
|
8
|
+
_id: string;
|
|
9
|
+
}>>;
|
|
10
|
+
getMetadata(): Promise<any>;
|
|
11
|
+
listRows(query: {
|
|
12
|
+
table: string;
|
|
13
|
+
page?: number;
|
|
14
|
+
page_size?: number;
|
|
15
|
+
view?: string;
|
|
16
|
+
}): Promise<{
|
|
17
|
+
rows: any[];
|
|
18
|
+
page?: number;
|
|
19
|
+
page_size?: number;
|
|
20
|
+
total?: number;
|
|
21
|
+
has_more?: boolean;
|
|
22
|
+
}>;
|
|
23
|
+
getRow(table: string, rowId: string): Promise<any>;
|
|
24
|
+
addRow(table: string, row: Record<string, unknown>): Promise<any>;
|
|
25
|
+
updateRow(table: string, rowId: string, row: Record<string, unknown>): Promise<any>;
|
|
26
|
+
deleteRow(table: string, rowId: string): Promise<{
|
|
27
|
+
success: boolean;
|
|
28
|
+
}>;
|
|
29
|
+
searchRows(table: string, query: Record<string, unknown>): Promise<{
|
|
30
|
+
rows: any[];
|
|
31
|
+
page?: number;
|
|
32
|
+
page_size?: number;
|
|
33
|
+
total?: number;
|
|
34
|
+
has_more?: boolean;
|
|
35
|
+
}>;
|
|
36
|
+
querySql(sql: string, parameters?: any[]): Promise<{
|
|
37
|
+
metadata: any;
|
|
38
|
+
results: any[];
|
|
39
|
+
}>;
|
|
40
|
+
listCollaborators(): Promise<Array<{
|
|
41
|
+
email: string;
|
|
42
|
+
name: string;
|
|
43
|
+
}>>;
|
|
44
|
+
createLinks(args: {
|
|
45
|
+
table: string;
|
|
46
|
+
linkColumn: string;
|
|
47
|
+
pairs: Array<{
|
|
48
|
+
fromRowId: string;
|
|
49
|
+
toRowId: string;
|
|
50
|
+
}>;
|
|
51
|
+
}): Promise<any>;
|
|
52
|
+
deleteLinks(args: {
|
|
53
|
+
table: string;
|
|
54
|
+
linkColumn: string;
|
|
55
|
+
pairs: Array<{
|
|
56
|
+
fromRowId: string;
|
|
57
|
+
toRowId: string;
|
|
58
|
+
}>;
|
|
59
|
+
}): Promise<any>;
|
|
60
|
+
addColumnOptions(args: {
|
|
61
|
+
table: string;
|
|
62
|
+
column: string;
|
|
63
|
+
options: Array<{
|
|
64
|
+
name: string;
|
|
65
|
+
color?: string;
|
|
66
|
+
textColor?: string;
|
|
67
|
+
}>;
|
|
68
|
+
}): Promise<any>;
|
|
69
|
+
uploadFile(args: {
|
|
70
|
+
table: string;
|
|
71
|
+
column: string;
|
|
72
|
+
rowId: string;
|
|
73
|
+
fileName: string;
|
|
74
|
+
fileData: string;
|
|
75
|
+
replace?: boolean;
|
|
76
|
+
}): Promise<{
|
|
77
|
+
file_name: string;
|
|
78
|
+
file_size: number;
|
|
79
|
+
asset_url: string;
|
|
80
|
+
column_type: string;
|
|
81
|
+
}>;
|
|
82
|
+
}
|
|
83
|
+
export type ToolDeps = {
|
|
84
|
+
client: ClientLike;
|
|
85
|
+
env: Env;
|
|
86
|
+
getInputSchema: (schema: any) => any;
|
|
87
|
+
baseNames?: string[];
|
|
88
|
+
};
|
|
89
|
+
export type ToolRegistrar = (server: McpServerLike, deps: ToolDeps) => void;
|
|
90
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/mcp/tools/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unlinkRows.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/unlinkRows.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAQ1C,eAAO,MAAM,kBAAkB,EAAE,aAqBhC,CAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const InputSchema = z.object({
|
|
3
|
+
table: z.string().describe('Source table name'),
|
|
4
|
+
link_column: z.string().describe('Name of the link column'),
|
|
5
|
+
pairs: z.array(z.object({ from_row_id: z.string().describe('Row ID in source table'), to_row_id: z.string().describe('Row ID in linked table') })).min(1).describe('Array of row ID pairs to unlink'),
|
|
6
|
+
});
|
|
7
|
+
export const registerUnlinkRows = (server, { client, getInputSchema }) => {
|
|
8
|
+
server.registerTool('unlink_rows', {
|
|
9
|
+
title: 'Unlink Rows',
|
|
10
|
+
description: 'Remove links between rows via the dedicated links endpoint. This is the ONLY way to remove links — link columns cannot be modified via update_rows.',
|
|
11
|
+
inputSchema: getInputSchema(InputSchema),
|
|
12
|
+
annotations: { readOnlyHint: false, destructiveHint: true },
|
|
13
|
+
}, async (args) => {
|
|
14
|
+
const { table, link_column, pairs } = InputSchema.parse(args);
|
|
15
|
+
const result = await client.deleteLinks({
|
|
16
|
+
table,
|
|
17
|
+
linkColumn: link_column,
|
|
18
|
+
pairs: pairs.map((p) => ({ fromRowId: p.from_row_id, toRowId: p.to_row_id })),
|
|
19
|
+
});
|
|
20
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=unlinkRows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unlinkRows.js","sourceRoot":"","sources":["../../../src/mcp/tools/unlinkRows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC;IAC/C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yBAAyB,CAAC;IAC3D,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,iCAAiC,CAAC;CACtM,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAkB,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,EAAE;IACtF,MAAM,CAAC,YAAY,CACjB,aAAa,EACb;QACE,KAAK,EAAE,aAAa;QACpB,WAAW,EAAE,qJAAqJ;QAClK,WAAW,EAAE,cAAc,CAAC,WAAW,CAAC;QACxC,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE;KAC5D,EACD,KAAK,EAAE,IAAa,EAAE,EAAE;QACtB,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAE7D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC;YACtC,KAAK;YACL,UAAU,EAAE,WAAW;YACvB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;SAC9E,CAAC,CAAA;QAEF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAA;IACtE,CAAC,CACF,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"updateRow.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/updateRow.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAY1C,eAAO,MAAM,kBAAkB,EAAE,aA4BhC,CAAA"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { mapMetadataToGeneric } from '../../schema/map.js';
|
|
3
|
+
import { validateRowsAgainstSchema } from '../../schema/validate.js';
|
|
4
|
+
const UpdateItem = z.object({
|
|
5
|
+
row_id: z.string().describe('Row ID (_id field) to update'),
|
|
6
|
+
values: z.record(z.any()).describe('Column name -> new value pairs'),
|
|
7
|
+
});
|
|
8
|
+
const InputSchema = z.object({
|
|
9
|
+
table: z.string().describe('Target table name'),
|
|
10
|
+
updates: z.array(UpdateItem).min(1).describe('Array of updates, each with row_id and values'),
|
|
11
|
+
});
|
|
12
|
+
export const registerUpdateRows = (server, { client, getInputSchema }) => {
|
|
13
|
+
server.registerTool('update_rows', {
|
|
14
|
+
title: 'Update Rows',
|
|
15
|
+
description: 'Batch update rows. Rejects unknown columns. Link and file/image columns cannot be modified here — use link_rows/unlink_rows and upload_file instead.',
|
|
16
|
+
inputSchema: getInputSchema(InputSchema),
|
|
17
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true },
|
|
18
|
+
}, async (args) => {
|
|
19
|
+
const { table, updates } = InputSchema.parse(args);
|
|
20
|
+
const metadata = await client.getMetadata();
|
|
21
|
+
const generic = mapMetadataToGeneric(metadata);
|
|
22
|
+
validateRowsAgainstSchema(generic, table, updates.map((u) => u.values));
|
|
23
|
+
const results = [];
|
|
24
|
+
for (const u of updates) {
|
|
25
|
+
await client.updateRow(table, u.row_id, u.values);
|
|
26
|
+
const fresh = await client.getRow(table, u.row_id);
|
|
27
|
+
results.push(fresh);
|
|
28
|
+
}
|
|
29
|
+
return { content: [{ type: 'text', text: JSON.stringify({ rows: results }) }] };
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=updateRow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"updateRow.js","sourceRoot":"","sources":["../../../src/mcp/tools/updateRow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC1D,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAA;AAGpE,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IACxB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;IAC3D,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,gCAAgC,CAAC;CACvE,CAAC,CAAA;AAEF,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IACzB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC;IAC/C,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,+CAA+C,CAAC;CAChG,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAkB,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,EAAE;IACpF,MAAM,CAAC,YAAY,CACf,aAAa,EACb;QACI,KAAK,EAAE,aAAa;QACpB,WAAW,EAAE,sJAAsJ;QACnK,WAAW,EAAE,cAAc,CAAC,WAAW,CAAC;QACxC,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE;KACrF,EACD,KAAK,EAAE,IAAa,EAAE,EAAE;QACpB,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAClD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAA;QAC3C,MAAM,OAAO,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAA;QAC9C,yBAAyB,CACrB,OAAO,EACP,KAAK,EACL,OAAO,CAAC,GAAG,CAAC,CAAC,CAA6B,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAC3D,CAAA;QAED,MAAM,OAAO,GAAG,EAAW,CAAA;QAC3B,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACtB,MAAM,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAA;YACjD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAA;YAClD,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACvB,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAA;IACnF,CAAC,CACJ,CAAA;AACL,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uploadFile.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/uploadFile.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAW1C,eAAO,MAAM,kBAAkB,EAAE,aAsBhC,CAAA"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const InputSchema = z.object({
|
|
3
|
+
table: z.string().describe('Target table name'),
|
|
4
|
+
column: z.string().describe('Name of the file or image column'),
|
|
5
|
+
row_id: z.string().describe('Row ID to attach the file to'),
|
|
6
|
+
file_name: z.string().describe('File name with extension (e.g. "report.pdf")'),
|
|
7
|
+
file_data: z.string().describe('Base64-encoded file content'),
|
|
8
|
+
replace: z.boolean().optional().default(false).describe('Replace existing files (default: append)'),
|
|
9
|
+
});
|
|
10
|
+
export const registerUploadFile = (server, { client, getInputSchema }) => {
|
|
11
|
+
server.registerTool('upload_file', {
|
|
12
|
+
title: 'Upload File',
|
|
13
|
+
description: 'Upload a file or image to a row. Accepts base64-encoded file data and attaches it to the specified file or image column. By default appends to existing files; set replace=true to overwrite.',
|
|
14
|
+
inputSchema: getInputSchema(InputSchema),
|
|
15
|
+
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
16
|
+
}, async (args) => {
|
|
17
|
+
const { table, column, row_id, file_name, file_data, replace } = InputSchema.parse(args);
|
|
18
|
+
const result = await client.uploadFile({
|
|
19
|
+
table,
|
|
20
|
+
column,
|
|
21
|
+
rowId: row_id,
|
|
22
|
+
fileName: file_name,
|
|
23
|
+
fileData: file_data,
|
|
24
|
+
replace,
|
|
25
|
+
});
|
|
26
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=uploadFile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uploadFile.js","sourceRoot":"","sources":["../../../src/mcp/tools/uploadFile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IACzB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC;IAC/C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;IAC/D,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;IAC3D,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;IAC9E,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;IAC7D,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,0CAA0C,CAAC;CACtG,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAkB,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,EAAE;IACpF,MAAM,CAAC,YAAY,CACf,aAAa,EACb;QACI,KAAK,EAAE,aAAa;QACpB,WAAW,EAAE,+LAA+L;QAC5M,WAAW,EAAE,cAAc,CAAC,WAAW,CAAC;QACxC,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE;KAC/D,EACD,KAAK,EAAE,IAAa,EAAE,EAAE;QACpB,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACxF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC;YACnC,KAAK;YACL,MAAM;YACN,KAAK,EAAE,MAAM;YACb,QAAQ,EAAE,SAAS;YACnB,QAAQ,EAAE,SAAS;YACnB,OAAO;SACV,CAAC,CAAA;QACF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAA;IACxE,CAAC,CACJ,CAAA;AACL,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upsertRows.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/upsertRows.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAQ1C,eAAO,MAAM,kBAAkB,EAAE,aAuDhC,CAAA"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { makeError } from '../../errors.js';
|
|
3
|
+
import { mapMetadataToGeneric } from '../../schema/map.js';
|
|
4
|
+
import { validateRowsAgainstSchema } from '../../schema/validate.js';
|
|
5
|
+
const InputSchema = z.object({
|
|
6
|
+
table: z.string().describe('Target table name'),
|
|
7
|
+
key_columns: z.array(z.string()).min(1).describe('Columns to match on for finding existing rows'),
|
|
8
|
+
rows: z.array(z.record(z.string(), z.any())).min(1).describe('Array of row objects (column name -> value)'),
|
|
9
|
+
});
|
|
10
|
+
export const registerUpsertRows = (server, { client, getInputSchema }) => {
|
|
11
|
+
server.registerTool('upsert_rows', {
|
|
12
|
+
title: 'Batch Upsert Rows',
|
|
13
|
+
description: 'Batch upsert rows by matching on one or more key columns. If a match exists, update it; otherwise insert a new row. Rejects unknown columns. Link and file/image columns cannot be set here — use link_rows/unlink_rows and upload_file instead.',
|
|
14
|
+
inputSchema: getInputSchema(InputSchema),
|
|
15
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true },
|
|
16
|
+
}, async (args) => {
|
|
17
|
+
const { table, key_columns, rows } = InputSchema.parse(args);
|
|
18
|
+
// Validate payload against schema
|
|
19
|
+
const metadata = await client.getMetadata();
|
|
20
|
+
const generic = mapMetadataToGeneric(metadata);
|
|
21
|
+
validateRowsAgainstSchema(generic, table, rows);
|
|
22
|
+
const results = [];
|
|
23
|
+
for (const row of rows) {
|
|
24
|
+
// Ensure all key columns present
|
|
25
|
+
for (const k of key_columns) {
|
|
26
|
+
if (!(k in row)) {
|
|
27
|
+
throw makeError('ERR_UPSERT_MISSING_KEY', `Missing key column in row: ${k}`, { key: k });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// Build simple equality filter
|
|
31
|
+
const filter = {};
|
|
32
|
+
for (const k of key_columns)
|
|
33
|
+
filter[k] = row[k];
|
|
34
|
+
const found = await client.searchRows(table, filter);
|
|
35
|
+
const matches = (found.rows || []).slice(0, 2);
|
|
36
|
+
if (matches.length > 1) {
|
|
37
|
+
throw makeError('ERR_UPSERT_AMBIGUOUS', 'Multiple matches for upsert key', {
|
|
38
|
+
key_columns,
|
|
39
|
+
filter,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
if (matches.length === 1) {
|
|
43
|
+
await client.updateRow(table, matches[0]._id, row);
|
|
44
|
+
const updated = await client.getRow(table, matches[0]._id);
|
|
45
|
+
results.push({ action: 'updated', row: updated });
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const inserted = await client.addRow(table, row);
|
|
49
|
+
results.push({ action: 'inserted', row: inserted });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { content: [{ type: 'text', text: JSON.stringify({ results }) }] };
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=upsertRows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upsertRows.js","sourceRoot":"","sources":["../../../src/mcp/tools/upsertRows.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tracks concurrent connections per key with a configurable limit.
|
|
3
|
+
*/
|
|
4
|
+
export declare class ConnectionCounter {
|
|
5
|
+
private readonly maxConnections;
|
|
6
|
+
private readonly counts;
|
|
7
|
+
constructor(maxConnections: number);
|
|
8
|
+
acquire(key: string): boolean;
|
|
9
|
+
release(key: string): void;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=connectionCounter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connectionCounter.d.ts","sourceRoot":"","sources":["../../src/ratelimit/connectionCounter.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,iBAAiB;IAC1B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAQ;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;gBAEvC,cAAc,EAAE,MAAM;IAIlC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAO7B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;CAQ7B"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tracks concurrent connections per key with a configurable limit.
|
|
3
|
+
*/
|
|
4
|
+
export class ConnectionCounter {
|
|
5
|
+
maxConnections;
|
|
6
|
+
counts = new Map();
|
|
7
|
+
constructor(maxConnections) {
|
|
8
|
+
this.maxConnections = maxConnections;
|
|
9
|
+
}
|
|
10
|
+
acquire(key) {
|
|
11
|
+
const current = this.counts.get(key) ?? 0;
|
|
12
|
+
if (current >= this.maxConnections)
|
|
13
|
+
return false;
|
|
14
|
+
this.counts.set(key, current + 1);
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
release(key) {
|
|
18
|
+
const current = this.counts.get(key) ?? 0;
|
|
19
|
+
if (current <= 1) {
|
|
20
|
+
this.counts.delete(key);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
this.counts.set(key, current - 1);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=connectionCounter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connectionCounter.js","sourceRoot":"","sources":["../../src/ratelimit/connectionCounter.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,iBAAiB;IACT,cAAc,CAAQ;IACtB,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAA;IAEnD,YAAY,cAAsB;QAC9B,IAAI,CAAC,cAAc,GAAG,cAAc,CAAA;IACxC,CAAC;IAED,OAAO,CAAC,GAAW;QACf,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACzC,IAAI,OAAO,IAAI,IAAI,CAAC,cAAc;YAAE,OAAO,KAAK,CAAA;QAChD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,GAAG,CAAC,CAAC,CAAA;QACjC,OAAO,IAAI,CAAA;IACf,CAAC;IAED,OAAO,CAAC,GAAW;QACf,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACzC,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC3B,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,GAAG,CAAC,CAAC,CAAA;QACrC,CAAC;IACL,CAAC;CACJ"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ConnectionCounter } from './connectionCounter.js';
|
|
2
|
+
import { SlidingWindowLimiter } from './rateLimiter.js';
|
|
3
|
+
export { ConnectionCounter } from './connectionCounter.js';
|
|
4
|
+
export { SlidingWindowLimiter } from './rateLimiter.js';
|
|
5
|
+
export interface RateLimitResult {
|
|
6
|
+
allowed: true;
|
|
7
|
+
}
|
|
8
|
+
export interface RateLimitDenied {
|
|
9
|
+
allowed: false;
|
|
10
|
+
retryAfterMs: number;
|
|
11
|
+
reason: string;
|
|
12
|
+
}
|
|
13
|
+
export declare class RateLimitManager {
|
|
14
|
+
readonly perToken: SlidingWindowLimiter;
|
|
15
|
+
readonly perIp: SlidingWindowLimiter;
|
|
16
|
+
readonly global: SlidingWindowLimiter;
|
|
17
|
+
readonly connections: ConnectionCounter;
|
|
18
|
+
private cleanupInterval?;
|
|
19
|
+
constructor();
|
|
20
|
+
check(opts: {
|
|
21
|
+
ip: string;
|
|
22
|
+
token?: string;
|
|
23
|
+
}): RateLimitResult | RateLimitDenied;
|
|
24
|
+
private cleanup;
|
|
25
|
+
destroy(): void;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ratelimit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AAEvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AAEvD,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,IAAI,CAAA;CAChB;AAED,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,KAAK,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;CACjB;AAID,qBAAa,gBAAgB;IACzB,QAAQ,CAAC,QAAQ,uBAA2C;IAC5D,QAAQ,CAAC,KAAK,uBAA4C;IAC1D,QAAQ,CAAC,MAAM,uBAA6C;IAC5D,QAAQ,CAAC,WAAW,oBAA2B;IAE/C,OAAO,CAAC,eAAe,CAAC,CAAgC;;IASxD,KAAK,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,eAAe,GAAG,eAAe;IAwB9E,OAAO,CAAC,OAAO;IAMf,OAAO,IAAI,IAAI;CAMlB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ConnectionCounter } from './connectionCounter.js';
|
|
2
|
+
import { SlidingWindowLimiter } from './rateLimiter.js';
|
|
3
|
+
export { ConnectionCounter } from './connectionCounter.js';
|
|
4
|
+
export { SlidingWindowLimiter } from './rateLimiter.js';
|
|
5
|
+
const ONE_MINUTE = 60_000;
|
|
6
|
+
export class RateLimitManager {
|
|
7
|
+
perToken = new SlidingWindowLimiter(60, ONE_MINUTE);
|
|
8
|
+
perIp = new SlidingWindowLimiter(120, ONE_MINUTE);
|
|
9
|
+
global = new SlidingWindowLimiter(5000, ONE_MINUTE);
|
|
10
|
+
connections = new ConnectionCounter(5);
|
|
11
|
+
cleanupInterval;
|
|
12
|
+
constructor() {
|
|
13
|
+
this.cleanupInterval = setInterval(() => this.cleanup(), 60_000);
|
|
14
|
+
if (this.cleanupInterval.unref) {
|
|
15
|
+
this.cleanupInterval.unref();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
check(opts) {
|
|
19
|
+
// Global limit
|
|
20
|
+
const globalResult = this.global.check('global');
|
|
21
|
+
if (!globalResult.allowed) {
|
|
22
|
+
return { allowed: false, retryAfterMs: globalResult.retryAfterMs, reason: 'Global rate limit exceeded' };
|
|
23
|
+
}
|
|
24
|
+
// Per-IP limit
|
|
25
|
+
const ipResult = this.perIp.check(opts.ip);
|
|
26
|
+
if (!ipResult.allowed) {
|
|
27
|
+
return { allowed: false, retryAfterMs: ipResult.retryAfterMs, reason: 'IP rate limit exceeded' };
|
|
28
|
+
}
|
|
29
|
+
// Per-token limit
|
|
30
|
+
if (opts.token) {
|
|
31
|
+
const tokenResult = this.perToken.check(opts.token);
|
|
32
|
+
if (!tokenResult.allowed) {
|
|
33
|
+
return { allowed: false, retryAfterMs: tokenResult.retryAfterMs, reason: 'Token rate limit exceeded' };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return { allowed: true };
|
|
37
|
+
}
|
|
38
|
+
cleanup() {
|
|
39
|
+
this.perToken.cleanup();
|
|
40
|
+
this.perIp.cleanup();
|
|
41
|
+
this.global.cleanup();
|
|
42
|
+
}
|
|
43
|
+
destroy() {
|
|
44
|
+
if (this.cleanupInterval) {
|
|
45
|
+
clearInterval(this.cleanupInterval);
|
|
46
|
+
this.cleanupInterval = undefined;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ratelimit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AAEvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AAYvD,MAAM,UAAU,GAAG,MAAM,CAAA;AAEzB,MAAM,OAAO,gBAAgB;IAChB,QAAQ,GAAG,IAAI,oBAAoB,CAAC,EAAE,EAAE,UAAU,CAAC,CAAA;IACnD,KAAK,GAAG,IAAI,oBAAoB,CAAC,GAAG,EAAE,UAAU,CAAC,CAAA;IACjD,MAAM,GAAG,IAAI,oBAAoB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;IACnD,WAAW,GAAG,IAAI,iBAAiB,CAAC,CAAC,CAAC,CAAA;IAEvC,eAAe,CAAiC;IAExD;QACI,IAAI,CAAC,eAAe,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC,CAAA;QAChE,IAAI,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;YAC7B,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAA;QAChC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAoC;QACtC,eAAe;QACf,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;QAChD,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;YACxB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,4BAA4B,EAAE,CAAA;QAC5G,CAAC;QAED,eAAe;QACf,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC1C,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAA;QACpG,CAAC;QAED,kBAAkB;QAClB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACnD,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;gBACvB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,2BAA2B,EAAE,CAAA;YAC1G,CAAC;QACL,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;IAC5B,CAAC;IAEO,OAAO;QACX,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAA;QACvB,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAA;QACpB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAA;IACzB,CAAC;IAED,OAAO;QACH,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACvB,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;YACnC,IAAI,CAAC,eAAe,GAAG,SAAS,CAAA;QACpC,CAAC;IACL,CAAC;CACJ"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sliding-window rate limiter using fixed-window approximation.
|
|
3
|
+
* No external dependencies.
|
|
4
|
+
*/
|
|
5
|
+
export declare class SlidingWindowLimiter {
|
|
6
|
+
private readonly maxRequests;
|
|
7
|
+
private readonly windowMs;
|
|
8
|
+
private readonly windows;
|
|
9
|
+
constructor(maxRequests: number, windowMs: number);
|
|
10
|
+
check(key: string): {
|
|
11
|
+
allowed: true;
|
|
12
|
+
} | {
|
|
13
|
+
allowed: false;
|
|
14
|
+
retryAfterMs: number;
|
|
15
|
+
};
|
|
16
|
+
cleanup(): void;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=rateLimiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rateLimiter.d.ts","sourceRoot":"","sources":["../../src/ratelimit/rateLimiter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,qBAAa,oBAAoB;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;gBAE7C,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IAKjD,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,OAAO,EAAE,KAAK,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE;IAoChF,OAAO,IAAI,IAAI;CASlB"}
|