@axiom-lattice/gateway 3.0.2 → 3.0.3
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/dist/index.js +31 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +31 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -6
- package/.eslintrc.json +0 -22
- package/.turbo/turbo-build.log +0 -46
- package/AGENTS.md +0 -112
- package/CHANGELOG.md +0 -1190
- package/LOGGER_CONFIG.md +0 -135
- package/RESUME_STREAM_CONTENT_BASED.md +0 -326
- package/RESUME_STREAM_README.md +0 -388
- package/jest.config.js +0 -72
- package/public/sdk/README.md +0 -695
- package/public/sdk/dashboard-engine-skill.md +0 -1122
- package/public/sdk/dashboard-single-file-spec.md +0 -357
- package/public/sdk/data-query-sdk-skill.md +0 -307
- package/public/sdk/data-query-sdk.d.ts +0 -252
- package/public/sdk/data-query-sdk.js +0 -970
- package/public/sdk/occupancy-dashboard.html +0 -363
- package/public/sdk/test-dashboard.html +0 -690
- package/scripts/seed-lark-installation.ts +0 -54
- package/src/__tests__/__mocks__/e2b.ts +0 -1
- package/src/__tests__/a2a.test.ts +0 -428
- package/src/__tests__/channel-installations.test.ts +0 -199
- package/src/__tests__/data-query.test.ts +0 -77
- package/src/__tests__/sandbox-provider-registration.test.ts +0 -74
- package/src/__tests__/setup.ts +0 -5
- package/src/__tests__/workspace.test.ts +0 -400
- package/src/channels/__tests__/routes.test.ts +0 -50
- package/src/channels/lark/LarkChannelAdapter.ts +0 -217
- package/src/channels/lark/README.md +0 -187
- package/src/channels/lark/__tests__/controller.test.ts +0 -136
- package/src/channels/lark/__tests__/mapping-service.test.ts +0 -118
- package/src/channels/lark/__tests__/parser.test.ts +0 -72
- package/src/channels/lark/__tests__/sender.test.ts +0 -37
- package/src/channels/lark/__tests__/verification.test.ts +0 -157
- package/src/channels/lark/controller.ts +0 -48
- package/src/channels/lark/mapping-service.ts +0 -138
- package/src/channels/lark/parser.ts +0 -68
- package/src/channels/lark/routes.ts +0 -22
- package/src/channels/lark/sender.ts +0 -58
- package/src/channels/lark/types.ts +0 -20
- package/src/channels/lark/verification.ts +0 -32
- package/src/channels/registry.ts +0 -20
- package/src/channels/routes.ts +0 -30
- package/src/channels/wechat/WechatChannelAdapter.ts +0 -294
- package/src/channels/wechat/__tests__/context-store.test.ts +0 -148
- package/src/channels/wechat/context-store.ts +0 -54
- package/src/channels/wechat/controller.ts +0 -59
- package/src/channels/wechat/routes.ts +0 -7
- package/src/channels/wechat/types.ts +0 -62
- package/src/channels/wechat/wechat-client.ts +0 -162
- package/src/config/local-a2a-templates.ts +0 -59
- package/src/config.ts +0 -124
- package/src/controllers/__tests__/assistant-local-a2a.test.ts +0 -147
- package/src/controllers/__tests__/local-a2a-templates.test.ts +0 -112
- package/src/controllers/__tests__/mime.test.ts +0 -74
- package/src/controllers/__tests__/resources.test.ts +0 -122
- package/src/controllers/__tests__/run.test.ts +0 -115
- package/src/controllers/__tests__/tasks.test.ts +0 -215
- package/src/controllers/__tests__/workflow-tracking.test.ts +0 -113
- package/src/controllers/agent_task.ts +0 -72
- package/src/controllers/assistant.ts +0 -490
- package/src/controllers/auth.ts +0 -524
- package/src/controllers/channel-bindings.ts +0 -135
- package/src/controllers/channel-installations.ts +0 -409
- package/src/controllers/collections.ts +0 -176
- package/src/controllers/config.ts +0 -126
- package/src/controllers/connections.ts +0 -181
- package/src/controllers/data-query.ts +0 -236
- package/src/controllers/database-configs.ts +0 -440
- package/src/controllers/embeddings.ts +0 -22
- package/src/controllers/entries.ts +0 -167
- package/src/controllers/eval.ts +0 -513
- package/src/controllers/export-import.ts +0 -166
- package/src/controllers/health.ts +0 -36
- package/src/controllers/local-a2a-templates.ts +0 -18
- package/src/controllers/local-a2a.ts +0 -149
- package/src/controllers/mcp-configs.ts +0 -673
- package/src/controllers/memory.ts +0 -257
- package/src/controllers/menu-items.ts +0 -114
- package/src/controllers/metrics-configs.ts +0 -1061
- package/src/controllers/middleware-types.ts +0 -15
- package/src/controllers/models.ts +0 -199
- package/src/controllers/personal-assistant.ts +0 -191
- package/src/controllers/resources.ts +0 -477
- package/src/controllers/run.ts +0 -338
- package/src/controllers/sandbox.ts +0 -255
- package/src/controllers/schedules.ts +0 -336
- package/src/controllers/skills.ts +0 -256
- package/src/controllers/tasks.ts +0 -213
- package/src/controllers/tenants.ts +0 -121
- package/src/controllers/thread_status.ts +0 -66
- package/src/controllers/threads.ts +0 -260
- package/src/controllers/tools.ts +0 -139
- package/src/controllers/users.ts +0 -135
- package/src/controllers/workflow-tracking.ts +0 -693
- package/src/controllers/workspace.ts +0 -879
- package/src/export_registrations/a2a-api-key.registration.ts +0 -89
- package/src/export_registrations/agent.registration.ts +0 -80
- package/src/export_registrations/binding.registration.ts +0 -106
- package/src/export_registrations/channel-installation.registration.ts +0 -88
- package/src/export_registrations/collection.registration.ts +0 -85
- package/src/export_registrations/connection.registration.ts +0 -97
- package/src/export_registrations/database-config.registration.ts +0 -94
- package/src/export_registrations/eval.registration.ts +0 -334
- package/src/export_registrations/index.ts +0 -31
- package/src/export_registrations/mcp-config.registration.ts +0 -97
- package/src/export_registrations/menu.registration.ts +0 -91
- package/src/export_registrations/metrics-config.registration.ts +0 -94
- package/src/export_registrations/skill.registration.ts +0 -88
- package/src/export_registrations/task.registration.ts +0 -99
- package/src/index.ts +0 -497
- package/src/logger/Logger.ts +0 -186
- package/src/router/MessageContext.ts +0 -14
- package/src/router/MessageRouter.ts +0 -490
- package/src/router/middlewares/auditLogger.ts +0 -34
- package/src/router/middlewares/deduplication.ts +0 -38
- package/src/router/middlewares/index.ts +0 -3
- package/src/router/middlewares/rateLimit.ts +0 -46
- package/src/routes/__tests__/a2a-test-connection.test.ts +0 -177
- package/src/routes/a2a-bridge.ts +0 -266
- package/src/routes/a2a-test-connection.ts +0 -126
- package/src/routes/a2a.ts +0 -851
- package/src/routes/channel-bindings.ts +0 -11
- package/src/routes/channel-installations.ts +0 -33
- package/src/routes/index.ts +0 -640
- package/src/routes/menu-items.ts +0 -10
- package/src/routes/resource-routes.ts +0 -35
- package/src/routes/stt.ts +0 -102
- package/src/schemas/data-query.ts +0 -69
- package/src/schemas/index.ts +0 -852
- package/src/services/ExportImportService.ts +0 -296
- package/src/services/__tests__/ExportImportService.test.ts +0 -130
- package/src/services/__tests__/eval-runner.test.ts +0 -131
- package/src/services/__tests__/local-a2a.test.ts +0 -124
- package/src/services/agent_task_consumer.ts +0 -348
- package/src/services/collection_service.ts +0 -258
- package/src/services/eval-runner.ts +0 -283
- package/src/services/local-a2a.ts +0 -354
- package/src/services/queue_service.ts +0 -104
- package/src/services/sandbox_service.ts +0 -223
- package/src/services/skill_service.ts +0 -97
- package/src/services/supabase.ts +0 -60
- package/src/swagger.ts +0 -77
- package/src/types/index.ts +0 -118
- package/src/types/koa.d.ts +0 -7
- package/src/utils/__tests__/local-a2a-runtime.test.ts +0 -77
- package/src/utils/__tests__/path-containment.test.ts +0 -35
- package/src/utils/a2a-url.ts +0 -20
- package/src/utils/local-a2a-runtime.ts +0 -107
- package/src/utils/mime.ts +0 -44
- package/src/utils/path-containment.ts +0 -38
- package/tsconfig.json +0 -26
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import type { FastifyInstance, FastifyRequest } from "fastify";
|
|
2
|
-
import { ConnectionRegistry, PluginRegistry } from "@axiom-lattice/core";
|
|
3
|
-
import { z } from "zod";
|
|
4
|
-
|
|
5
|
-
const createBody = z.object({
|
|
6
|
-
type: z.string().min(1),
|
|
7
|
-
key: z.string().min(1),
|
|
8
|
-
name: z.string().min(1),
|
|
9
|
-
description: z.string().optional(),
|
|
10
|
-
config: z.record(z.unknown()),
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
const testOrDiscoverBody = z.object({
|
|
14
|
-
key: z.string().optional(),
|
|
15
|
-
config: z.record(z.unknown()).optional(),
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
function getTenant(request: FastifyRequest): string {
|
|
19
|
-
// First try to get from authenticated user context
|
|
20
|
-
const userTenantId = (request as any).user?.tenantId;
|
|
21
|
-
if (userTenantId) {
|
|
22
|
-
return userTenantId;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Fallback to request headers for backward compatibility
|
|
26
|
-
return (request.headers["x-tenant-id"] as string) || "default";
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function maskSecrets(config: Record<string, unknown>): Record<string, unknown> {
|
|
30
|
-
const sensitive = new Set([
|
|
31
|
-
"password", "secret", "token", "apikey", "api_key", "session",
|
|
32
|
-
"privatekey", "private_key", "accesskey", "access_key",
|
|
33
|
-
]);
|
|
34
|
-
const out: Record<string, unknown> = {};
|
|
35
|
-
for (const [k, v] of Object.entries(config)) {
|
|
36
|
-
out[k] = sensitive.has(k.toLowerCase()) ? "********" : v;
|
|
37
|
-
}
|
|
38
|
-
return out;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/** Resolve target config: stored connection (by key) takes priority over inline config */
|
|
42
|
-
async function resolveConfig(
|
|
43
|
-
type: string, body: { key?: string; config?: Record<string, unknown> }, tenantId: string,
|
|
44
|
-
): Promise<Record<string, unknown>> {
|
|
45
|
-
if (body.key) {
|
|
46
|
-
const entry = await ConnectionRegistry.get(type, body.key, tenantId);
|
|
47
|
-
if (!entry) throw { status: 404, error: `Connection "${body.key}" not found` };
|
|
48
|
-
return entry.config;
|
|
49
|
-
}
|
|
50
|
-
if (body.config) return body.config;
|
|
51
|
-
throw { status: 400, error: "Either 'key' or 'config' is required" };
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function connectionRoutes(fastify: FastifyInstance): void {
|
|
55
|
-
// List connections by type
|
|
56
|
-
fastify.get("/api/connections", async (request, reply) => {
|
|
57
|
-
const { type } = request.query as { type?: string };
|
|
58
|
-
if (!type) return reply.status(400).send({ error: "query 'type' required" });
|
|
59
|
-
const entries = await ConnectionRegistry.list(type, getTenant(request));
|
|
60
|
-
return reply.send({
|
|
61
|
-
success: true,
|
|
62
|
-
data: { records: entries.map((e) => ({ ...e, config: maskSecrets(e.config) })), total: entries.length },
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
// Create connection
|
|
67
|
-
fastify.post("/api/connections", async (request, reply) => {
|
|
68
|
-
const parsed = createBody.parse(request.body);
|
|
69
|
-
const entry = await ConnectionRegistry.create({
|
|
70
|
-
tenantId: getTenant(request),
|
|
71
|
-
type: parsed.type,
|
|
72
|
-
key: parsed.key,
|
|
73
|
-
name: parsed.name,
|
|
74
|
-
description: parsed.description,
|
|
75
|
-
config: parsed.config,
|
|
76
|
-
});
|
|
77
|
-
return reply.status(201).send({
|
|
78
|
-
success: true,
|
|
79
|
-
data: { ...entry, config: maskSecrets(entry.config) },
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
// Update connection (type in query, key in path)
|
|
84
|
-
fastify.put("/api/connections/:key", async (request, reply) => {
|
|
85
|
-
const { type } = request.query as { type?: string };
|
|
86
|
-
if (!type) return reply.status(400).send({ error: "query 'type' required" });
|
|
87
|
-
|
|
88
|
-
const { key } = request.params as { key: string };
|
|
89
|
-
const body = request.body as Record<string, unknown>;
|
|
90
|
-
const tenantId = getTenant(request);
|
|
91
|
-
|
|
92
|
-
const existing = await ConnectionRegistry.get(type, key, tenantId);
|
|
93
|
-
if (!existing) return reply.status(404).send({ error: "not found" });
|
|
94
|
-
|
|
95
|
-
const updates: Record<string, unknown> = {};
|
|
96
|
-
if (body.name !== undefined) updates.name = body.name;
|
|
97
|
-
if (body.description !== undefined) updates.description = body.description;
|
|
98
|
-
if (body.config) {
|
|
99
|
-
updates.config = { ...existing.config, ...(body.config as Record<string, unknown>) };
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const entry = await ConnectionRegistry.update(tenantId, type, key, updates);
|
|
103
|
-
return reply.send({
|
|
104
|
-
success: true,
|
|
105
|
-
data: { ...entry, config: maskSecrets(entry?.config ?? {}) },
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
// Delete connection
|
|
110
|
-
fastify.delete("/api/connections/:key", async (request, reply) => {
|
|
111
|
-
const { type } = request.query as { type?: string };
|
|
112
|
-
if (!type) return reply.status(400).send({ error: "query 'type' required" });
|
|
113
|
-
|
|
114
|
-
const { key } = request.params as { key: string };
|
|
115
|
-
const ok = await ConnectionRegistry.delete(getTenant(request), type, key);
|
|
116
|
-
return reply.send({ success: ok });
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
// Test connection (supports key-based stored connection or inline config)
|
|
120
|
-
fastify.post("/api/connections/test", async (request, reply) => {
|
|
121
|
-
const { type } = request.query as { type: string };
|
|
122
|
-
if (!type) return reply.status(400).send({ error: "query 'type' required" });
|
|
123
|
-
|
|
124
|
-
const plugin = PluginRegistry.get(type);
|
|
125
|
-
if (!plugin?.connection?.test) {
|
|
126
|
-
return reply.status(400).send({ error: "plugin does not support connection testing" });
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
try {
|
|
130
|
-
const body = testOrDiscoverBody.parse(request.body);
|
|
131
|
-
const targetConfig = await resolveConfig(type, body, getTenant(request));
|
|
132
|
-
const result = await plugin.connection.test(targetConfig);
|
|
133
|
-
return reply.send(result);
|
|
134
|
-
} catch (err) {
|
|
135
|
-
if ((err as Record<string, unknown>)?.status === 404) {
|
|
136
|
-
return reply.status(404).send(err);
|
|
137
|
-
}
|
|
138
|
-
if ((err as Record<string, unknown>)?.status === 400) {
|
|
139
|
-
return reply.status(400).send(err);
|
|
140
|
-
}
|
|
141
|
-
if (err instanceof z.ZodError) {
|
|
142
|
-
return reply.status(400).send({ error: err.errors });
|
|
143
|
-
}
|
|
144
|
-
return reply.status(500).send({
|
|
145
|
-
ok: false,
|
|
146
|
-
message: err instanceof Error ? err.message : String(err),
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
// Resource discovery (supports key-based stored connection or inline config)
|
|
152
|
-
fastify.post("/api/connections/discover", async (request, reply) => {
|
|
153
|
-
const { type } = request.query as { type: string };
|
|
154
|
-
if (!type) return reply.status(400).send({ error: "query 'type' required" });
|
|
155
|
-
|
|
156
|
-
const plugin = PluginRegistry.get(type);
|
|
157
|
-
if (!plugin?.connection?.discover) {
|
|
158
|
-
return reply.status(400).send({ error: "plugin does not support resource discovery" });
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
try {
|
|
162
|
-
const body = testOrDiscoverBody.parse(request.body);
|
|
163
|
-
const targetConfig = await resolveConfig(type, body, getTenant(request));
|
|
164
|
-
const resources = await plugin.connection.discover(targetConfig);
|
|
165
|
-
return reply.send({ resources });
|
|
166
|
-
} catch (err) {
|
|
167
|
-
if ((err as Record<string, unknown>)?.status === 404) {
|
|
168
|
-
return reply.status(404).send(err);
|
|
169
|
-
}
|
|
170
|
-
if ((err as Record<string, unknown>)?.status === 400) {
|
|
171
|
-
return reply.status(400).send(err);
|
|
172
|
-
}
|
|
173
|
-
if (err instanceof z.ZodError) {
|
|
174
|
-
return reply.status(400).send({ error: err.errors });
|
|
175
|
-
}
|
|
176
|
-
return reply.status(500).send({
|
|
177
|
-
error: err instanceof Error ? err.message : String(err),
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
}
|
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
import { FastifyRequest, FastifyReply } from "fastify";
|
|
2
|
-
import {
|
|
3
|
-
getStoreLattice,
|
|
4
|
-
metricsServerManager,
|
|
5
|
-
SemanticMetricsClient,
|
|
6
|
-
} from "@axiom-lattice/core";
|
|
7
|
-
import type {
|
|
8
|
-
MetricsServerConfigStore,
|
|
9
|
-
SemanticMetricsServerConfig,
|
|
10
|
-
SemanticMetricsFilter,
|
|
11
|
-
} from "@axiom-lattice/protocols";
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Get tenant ID from request headers
|
|
15
|
-
*/
|
|
16
|
-
function getTenantId(request: FastifyRequest): string {
|
|
17
|
-
return (request.headers["x-tenant-id"] as string) || "default";
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Data query request body
|
|
22
|
-
*/
|
|
23
|
-
interface DataQueryRequest {
|
|
24
|
-
serverKey?: string;
|
|
25
|
-
datasourceId?: string;
|
|
26
|
-
metrics?: string[];
|
|
27
|
-
groupBy?: string[];
|
|
28
|
-
filters?: Array<{
|
|
29
|
-
dimension: string;
|
|
30
|
-
operator: string;
|
|
31
|
-
values: (string | number | boolean)[];
|
|
32
|
-
}>;
|
|
33
|
-
customSql?: string;
|
|
34
|
-
params?: Record<string, string | number | boolean>;
|
|
35
|
-
limit?: number;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Data query response - 只返回原始数据
|
|
40
|
-
*/
|
|
41
|
-
interface DataQueryResponse {
|
|
42
|
-
success: boolean;
|
|
43
|
-
message: string;
|
|
44
|
-
data?: {
|
|
45
|
-
// 语义查询结果
|
|
46
|
-
semanticModel?: string;
|
|
47
|
-
columns: Array<{ name: string; type: string }>;
|
|
48
|
-
rows?: Array<Array<unknown>>;
|
|
49
|
-
rowsObject?: Array<Record<string, unknown>>;
|
|
50
|
-
// SQL 查询结果
|
|
51
|
-
tableName?: string;
|
|
52
|
-
executedSql?: string;
|
|
53
|
-
// 通用元数据
|
|
54
|
-
metadata: {
|
|
55
|
-
rowCount: number;
|
|
56
|
-
executionTimeMs?: number;
|
|
57
|
-
};
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Execute data query (semantic or SQL)
|
|
63
|
-
*/
|
|
64
|
-
export async function executeDataQuery(
|
|
65
|
-
request: FastifyRequest,
|
|
66
|
-
reply: FastifyReply
|
|
67
|
-
): Promise<DataQueryResponse> {
|
|
68
|
-
const tenantId = getTenantId(request);
|
|
69
|
-
const body = request.body as DataQueryRequest;
|
|
70
|
-
|
|
71
|
-
try {
|
|
72
|
-
// Validate request
|
|
73
|
-
if (!body.serverKey && !body.datasourceId) {
|
|
74
|
-
reply.code(400);
|
|
75
|
-
return {
|
|
76
|
-
success: false,
|
|
77
|
-
message: "Either serverKey or datasourceId must be provided",
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Determine query type
|
|
82
|
-
const isSemanticQuery = body.metrics && body.metrics.length > 0;
|
|
83
|
-
const isSqlQuery = body.customSql && body.customSql.trim().length > 0;
|
|
84
|
-
|
|
85
|
-
if (!isSemanticQuery && !isSqlQuery) {
|
|
86
|
-
reply.code(400);
|
|
87
|
-
return {
|
|
88
|
-
success: false,
|
|
89
|
-
message: "Either metrics (for semantic query) or customSql (for SQL query) must be provided",
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (isSemanticQuery && isSqlQuery) {
|
|
94
|
-
reply.code(400);
|
|
95
|
-
return {
|
|
96
|
-
success: false,
|
|
97
|
-
message: "Cannot provide both metrics and customSql. Use one query type only.",
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Get server config
|
|
102
|
-
const storeLattice = getStoreLattice("default", "metrics");
|
|
103
|
-
const store: MetricsServerConfigStore = storeLattice.store;
|
|
104
|
-
|
|
105
|
-
if (!body.serverKey) {
|
|
106
|
-
reply.code(400);
|
|
107
|
-
return {
|
|
108
|
-
success: false,
|
|
109
|
-
message: "serverKey is required",
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const config = await store.getConfigByKey(tenantId, body.serverKey);
|
|
114
|
-
if (!config) {
|
|
115
|
-
reply.code(404);
|
|
116
|
-
return {
|
|
117
|
-
success: false,
|
|
118
|
-
message: `Metrics server configuration not found: ${body.serverKey}`,
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (config.config.type !== "semantic") {
|
|
123
|
-
reply.code(400);
|
|
124
|
-
return {
|
|
125
|
-
success: false,
|
|
126
|
-
message: "This endpoint only supports semantic metrics servers",
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (!body.datasourceId) {
|
|
131
|
-
reply.code(400);
|
|
132
|
-
return {
|
|
133
|
-
success: false,
|
|
134
|
-
message: "datasourceId is required",
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Get client from manager (queries store for latest config)
|
|
139
|
-
let client: SemanticMetricsClient;
|
|
140
|
-
try {
|
|
141
|
-
client = await metricsServerManager.getClient(tenantId, body.serverKey) as SemanticMetricsClient;
|
|
142
|
-
} catch {
|
|
143
|
-
reply.code(400);
|
|
144
|
-
return {
|
|
145
|
-
success: false,
|
|
146
|
-
message: `Metrics server not registered: ${body.serverKey}. Please register the server first.`,
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Execute query based on type
|
|
151
|
-
if (isSemanticQuery) {
|
|
152
|
-
return await executeSemanticQuery(client, body, reply);
|
|
153
|
-
} else {
|
|
154
|
-
return await executeSqlQuery(client, body, reply);
|
|
155
|
-
}
|
|
156
|
-
} catch (error) {
|
|
157
|
-
console.error("Failed to execute data query:", error);
|
|
158
|
-
reply.code(500);
|
|
159
|
-
return {
|
|
160
|
-
success: false,
|
|
161
|
-
message: `Failed to execute data query: ${error instanceof Error ? error.message : String(error)}`,
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Execute semantic query
|
|
168
|
-
*/
|
|
169
|
-
async function executeSemanticQuery(
|
|
170
|
-
client: SemanticMetricsClient,
|
|
171
|
-
body: DataQueryRequest,
|
|
172
|
-
reply: FastifyReply
|
|
173
|
-
): Promise<DataQueryResponse> {
|
|
174
|
-
const semanticFilters: SemanticMetricsFilter[] = (body.filters || []).map(f => ({
|
|
175
|
-
dimension: f.dimension,
|
|
176
|
-
operator: f.operator,
|
|
177
|
-
values: f.values,
|
|
178
|
-
}));
|
|
179
|
-
|
|
180
|
-
const result = await client.semanticQuery({
|
|
181
|
-
datasourceId: body.datasourceId!,
|
|
182
|
-
metrics: body.metrics!,
|
|
183
|
-
groupBy: body.groupBy,
|
|
184
|
-
filters: semanticFilters,
|
|
185
|
-
limit: body.limit || 1000,
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
// 直接返回原始数据,不做 ECharts 转换
|
|
189
|
-
return {
|
|
190
|
-
success: true,
|
|
191
|
-
message: "Semantic query executed successfully",
|
|
192
|
-
data: {
|
|
193
|
-
semanticModel: result.semanticModel,
|
|
194
|
-
columns: result.columns,
|
|
195
|
-
rows: result.rows,
|
|
196
|
-
rowsObject: result.rowsObject,
|
|
197
|
-
metadata: {
|
|
198
|
-
rowCount: result.rowCount,
|
|
199
|
-
executionTimeMs: result.executionTimeMs,
|
|
200
|
-
},
|
|
201
|
-
},
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Execute SQL query
|
|
207
|
-
*/
|
|
208
|
-
async function executeSqlQuery(
|
|
209
|
-
client: SemanticMetricsClient,
|
|
210
|
-
body: DataQueryRequest,
|
|
211
|
-
reply: FastifyReply
|
|
212
|
-
): Promise<DataQueryResponse> {
|
|
213
|
-
const result = await client.executeSqlQuery({
|
|
214
|
-
datasourceId: body.datasourceId!,
|
|
215
|
-
customSql: body.customSql!,
|
|
216
|
-
params: body.params,
|
|
217
|
-
limit: body.limit || 100,
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
// 直接返回原始数据,不做 ECharts 转换
|
|
221
|
-
return {
|
|
222
|
-
success: true,
|
|
223
|
-
message: "SQL query executed successfully",
|
|
224
|
-
data: {
|
|
225
|
-
tableName: result.tableName,
|
|
226
|
-
columns: result.columns.map(name => ({ name, type: 'unknown' })),
|
|
227
|
-
rows: result.rows,
|
|
228
|
-
rowsObject: result.rowsObject,
|
|
229
|
-
executedSql: result.executedSql,
|
|
230
|
-
metadata: {
|
|
231
|
-
rowCount: result.rowCount,
|
|
232
|
-
executionTimeMs: result.executionTimeMs,
|
|
233
|
-
},
|
|
234
|
-
},
|
|
235
|
-
};
|
|
236
|
-
}
|