@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.
Files changed (155) hide show
  1. package/dist/index.js +31 -9
  2. package/dist/index.js.map +1 -1
  3. package/dist/index.mjs +31 -9
  4. package/dist/index.mjs.map +1 -1
  5. package/package.json +9 -6
  6. package/.eslintrc.json +0 -22
  7. package/.turbo/turbo-build.log +0 -46
  8. package/AGENTS.md +0 -112
  9. package/CHANGELOG.md +0 -1190
  10. package/LOGGER_CONFIG.md +0 -135
  11. package/RESUME_STREAM_CONTENT_BASED.md +0 -326
  12. package/RESUME_STREAM_README.md +0 -388
  13. package/jest.config.js +0 -72
  14. package/public/sdk/README.md +0 -695
  15. package/public/sdk/dashboard-engine-skill.md +0 -1122
  16. package/public/sdk/dashboard-single-file-spec.md +0 -357
  17. package/public/sdk/data-query-sdk-skill.md +0 -307
  18. package/public/sdk/data-query-sdk.d.ts +0 -252
  19. package/public/sdk/data-query-sdk.js +0 -970
  20. package/public/sdk/occupancy-dashboard.html +0 -363
  21. package/public/sdk/test-dashboard.html +0 -690
  22. package/scripts/seed-lark-installation.ts +0 -54
  23. package/src/__tests__/__mocks__/e2b.ts +0 -1
  24. package/src/__tests__/a2a.test.ts +0 -428
  25. package/src/__tests__/channel-installations.test.ts +0 -199
  26. package/src/__tests__/data-query.test.ts +0 -77
  27. package/src/__tests__/sandbox-provider-registration.test.ts +0 -74
  28. package/src/__tests__/setup.ts +0 -5
  29. package/src/__tests__/workspace.test.ts +0 -400
  30. package/src/channels/__tests__/routes.test.ts +0 -50
  31. package/src/channels/lark/LarkChannelAdapter.ts +0 -217
  32. package/src/channels/lark/README.md +0 -187
  33. package/src/channels/lark/__tests__/controller.test.ts +0 -136
  34. package/src/channels/lark/__tests__/mapping-service.test.ts +0 -118
  35. package/src/channels/lark/__tests__/parser.test.ts +0 -72
  36. package/src/channels/lark/__tests__/sender.test.ts +0 -37
  37. package/src/channels/lark/__tests__/verification.test.ts +0 -157
  38. package/src/channels/lark/controller.ts +0 -48
  39. package/src/channels/lark/mapping-service.ts +0 -138
  40. package/src/channels/lark/parser.ts +0 -68
  41. package/src/channels/lark/routes.ts +0 -22
  42. package/src/channels/lark/sender.ts +0 -58
  43. package/src/channels/lark/types.ts +0 -20
  44. package/src/channels/lark/verification.ts +0 -32
  45. package/src/channels/registry.ts +0 -20
  46. package/src/channels/routes.ts +0 -30
  47. package/src/channels/wechat/WechatChannelAdapter.ts +0 -294
  48. package/src/channels/wechat/__tests__/context-store.test.ts +0 -148
  49. package/src/channels/wechat/context-store.ts +0 -54
  50. package/src/channels/wechat/controller.ts +0 -59
  51. package/src/channels/wechat/routes.ts +0 -7
  52. package/src/channels/wechat/types.ts +0 -62
  53. package/src/channels/wechat/wechat-client.ts +0 -162
  54. package/src/config/local-a2a-templates.ts +0 -59
  55. package/src/config.ts +0 -124
  56. package/src/controllers/__tests__/assistant-local-a2a.test.ts +0 -147
  57. package/src/controllers/__tests__/local-a2a-templates.test.ts +0 -112
  58. package/src/controllers/__tests__/mime.test.ts +0 -74
  59. package/src/controllers/__tests__/resources.test.ts +0 -122
  60. package/src/controllers/__tests__/run.test.ts +0 -115
  61. package/src/controllers/__tests__/tasks.test.ts +0 -215
  62. package/src/controllers/__tests__/workflow-tracking.test.ts +0 -113
  63. package/src/controllers/agent_task.ts +0 -72
  64. package/src/controllers/assistant.ts +0 -490
  65. package/src/controllers/auth.ts +0 -524
  66. package/src/controllers/channel-bindings.ts +0 -135
  67. package/src/controllers/channel-installations.ts +0 -409
  68. package/src/controllers/collections.ts +0 -176
  69. package/src/controllers/config.ts +0 -126
  70. package/src/controllers/connections.ts +0 -181
  71. package/src/controllers/data-query.ts +0 -236
  72. package/src/controllers/database-configs.ts +0 -440
  73. package/src/controllers/embeddings.ts +0 -22
  74. package/src/controllers/entries.ts +0 -167
  75. package/src/controllers/eval.ts +0 -513
  76. package/src/controllers/export-import.ts +0 -166
  77. package/src/controllers/health.ts +0 -36
  78. package/src/controllers/local-a2a-templates.ts +0 -18
  79. package/src/controllers/local-a2a.ts +0 -149
  80. package/src/controllers/mcp-configs.ts +0 -673
  81. package/src/controllers/memory.ts +0 -257
  82. package/src/controllers/menu-items.ts +0 -114
  83. package/src/controllers/metrics-configs.ts +0 -1061
  84. package/src/controllers/middleware-types.ts +0 -15
  85. package/src/controllers/models.ts +0 -199
  86. package/src/controllers/personal-assistant.ts +0 -191
  87. package/src/controllers/resources.ts +0 -477
  88. package/src/controllers/run.ts +0 -338
  89. package/src/controllers/sandbox.ts +0 -255
  90. package/src/controllers/schedules.ts +0 -336
  91. package/src/controllers/skills.ts +0 -256
  92. package/src/controllers/tasks.ts +0 -213
  93. package/src/controllers/tenants.ts +0 -121
  94. package/src/controllers/thread_status.ts +0 -66
  95. package/src/controllers/threads.ts +0 -260
  96. package/src/controllers/tools.ts +0 -139
  97. package/src/controllers/users.ts +0 -135
  98. package/src/controllers/workflow-tracking.ts +0 -693
  99. package/src/controllers/workspace.ts +0 -879
  100. package/src/export_registrations/a2a-api-key.registration.ts +0 -89
  101. package/src/export_registrations/agent.registration.ts +0 -80
  102. package/src/export_registrations/binding.registration.ts +0 -106
  103. package/src/export_registrations/channel-installation.registration.ts +0 -88
  104. package/src/export_registrations/collection.registration.ts +0 -85
  105. package/src/export_registrations/connection.registration.ts +0 -97
  106. package/src/export_registrations/database-config.registration.ts +0 -94
  107. package/src/export_registrations/eval.registration.ts +0 -334
  108. package/src/export_registrations/index.ts +0 -31
  109. package/src/export_registrations/mcp-config.registration.ts +0 -97
  110. package/src/export_registrations/menu.registration.ts +0 -91
  111. package/src/export_registrations/metrics-config.registration.ts +0 -94
  112. package/src/export_registrations/skill.registration.ts +0 -88
  113. package/src/export_registrations/task.registration.ts +0 -99
  114. package/src/index.ts +0 -497
  115. package/src/logger/Logger.ts +0 -186
  116. package/src/router/MessageContext.ts +0 -14
  117. package/src/router/MessageRouter.ts +0 -490
  118. package/src/router/middlewares/auditLogger.ts +0 -34
  119. package/src/router/middlewares/deduplication.ts +0 -38
  120. package/src/router/middlewares/index.ts +0 -3
  121. package/src/router/middlewares/rateLimit.ts +0 -46
  122. package/src/routes/__tests__/a2a-test-connection.test.ts +0 -177
  123. package/src/routes/a2a-bridge.ts +0 -266
  124. package/src/routes/a2a-test-connection.ts +0 -126
  125. package/src/routes/a2a.ts +0 -851
  126. package/src/routes/channel-bindings.ts +0 -11
  127. package/src/routes/channel-installations.ts +0 -33
  128. package/src/routes/index.ts +0 -640
  129. package/src/routes/menu-items.ts +0 -10
  130. package/src/routes/resource-routes.ts +0 -35
  131. package/src/routes/stt.ts +0 -102
  132. package/src/schemas/data-query.ts +0 -69
  133. package/src/schemas/index.ts +0 -852
  134. package/src/services/ExportImportService.ts +0 -296
  135. package/src/services/__tests__/ExportImportService.test.ts +0 -130
  136. package/src/services/__tests__/eval-runner.test.ts +0 -131
  137. package/src/services/__tests__/local-a2a.test.ts +0 -124
  138. package/src/services/agent_task_consumer.ts +0 -348
  139. package/src/services/collection_service.ts +0 -258
  140. package/src/services/eval-runner.ts +0 -283
  141. package/src/services/local-a2a.ts +0 -354
  142. package/src/services/queue_service.ts +0 -104
  143. package/src/services/sandbox_service.ts +0 -223
  144. package/src/services/skill_service.ts +0 -97
  145. package/src/services/supabase.ts +0 -60
  146. package/src/swagger.ts +0 -77
  147. package/src/types/index.ts +0 -118
  148. package/src/types/koa.d.ts +0 -7
  149. package/src/utils/__tests__/local-a2a-runtime.test.ts +0 -77
  150. package/src/utils/__tests__/path-containment.test.ts +0 -35
  151. package/src/utils/a2a-url.ts +0 -20
  152. package/src/utils/local-a2a-runtime.ts +0 -107
  153. package/src/utils/mime.ts +0 -44
  154. package/src/utils/path-containment.ts +0 -38
  155. package/tsconfig.json +0 -26
@@ -1,1061 +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
- MetricsServerConfigEntry,
10
- CreateMetricsServerConfigRequest,
11
- UpdateMetricsServerConfigRequest,
12
- MetricsServerConfig,
13
- DataSource,
14
- SemanticMetricsQueryRequest,
15
- SemanticMetricsServerConfig,
16
- } from "@axiom-lattice/protocols";
17
- import { randomUUID } from "crypto";
18
-
19
- /**
20
- * Metrics Server Config Controller
21
- * Handles metrics server configuration CRUD operations
22
- */
23
-
24
- /**
25
- * Get tenant ID from authenticated user context
26
- * Falls back to request headers for backward compatibility
27
- */
28
- function getTenantId(request: FastifyRequest): string {
29
- // First try to get from authenticated user context
30
- const userTenantId = (request as any).user?.tenantId;
31
- if (userTenantId) {
32
- return userTenantId;
33
- }
34
-
35
- // Fallback to request headers for backward compatibility
36
- return (request.headers["x-tenant-id"] as string) || "default";
37
- }
38
-
39
- /**
40
- * Metrics server config list response
41
- */
42
- interface MetricsServerConfigListResponse {
43
- success: boolean;
44
- message: string;
45
- data: {
46
- records: MetricsServerConfigEntry[];
47
- total: number;
48
- };
49
- }
50
-
51
- /**
52
- * Metrics server config response
53
- */
54
- interface MetricsServerConfigResponse {
55
- success: boolean;
56
- message: string;
57
- data?: MetricsServerConfigEntry;
58
- }
59
-
60
- /**
61
- * Test connection response
62
- */
63
- interface TestConnectionResponse {
64
- success: boolean;
65
- message: string;
66
- data?: {
67
- connected: boolean;
68
- latency?: number;
69
- error?: string;
70
- };
71
- }
72
-
73
- /**
74
- * List available metrics response
75
- */
76
- interface ListMetricsResponse {
77
- success: boolean;
78
- message: string;
79
- data?: {
80
- metrics: Array<{
81
- name: string;
82
- type?: string;
83
- description?: string;
84
- }>;
85
- };
86
- }
87
-
88
- /**
89
- * Query metric data response
90
- */
91
- interface QueryMetricDataResponse {
92
- success: boolean;
93
- message: string;
94
- data?: {
95
- metricName: string;
96
- dataPoints: Array<{
97
- timestamp: number;
98
- value: number;
99
- labels?: Record<string, string>;
100
- }>;
101
- };
102
- }
103
-
104
- /**
105
- * Data sources list response
106
- */
107
- interface DataSourcesResponse {
108
- success: boolean;
109
- message: string;
110
- data?: {
111
- datasources: DataSource[];
112
- };
113
- }
114
-
115
- /**
116
- * Datasource metrics response
117
- */
118
- interface DatasourceMetricsResponse {
119
- success: boolean;
120
- message: string;
121
- data?: {
122
- index: {
123
- datasourceId: number;
124
- datasourceName: string;
125
- catalogVersion: string;
126
- domainCategories: string[];
127
- metrics: Array<{
128
- metricName: string;
129
- displayName: string;
130
- domain: string;
131
- shortDesc: string;
132
- searchKeywords: string[];
133
- registered: boolean;
134
- }>;
135
- tables?: Array<{
136
- tableName: string;
137
- displayName: string;
138
- docType: string;
139
- docTypeEn: string;
140
- mainTable?: string;
141
- lineTable?: string;
142
- columnCount: number;
143
- shortDesc: string;
144
- }>;
145
- };
146
- metricsDetails: Array<{
147
- datasourceId: number;
148
- metricName: string;
149
- displayName: string;
150
- domain: string;
151
- description: string;
152
- dataType: string;
153
- format: string;
154
- defaultTimeContext: {
155
- timeDimension: string;
156
- label: string;
157
- granularity: string;
158
- window: string;
159
- supportedGrains: string[];
160
- };
161
- supportedDimensions: Array<{
162
- dim_id: string;
163
- field_name: string;
164
- type: string;
165
- filter_operators?: string[];
166
- filter_example?: object;
167
- group_by_example?: string;
168
- }>;
169
- aiAgentContext: {
170
- polarity: string;
171
- synonyms: string[];
172
- thresholds: Array<{
173
- metric: string;
174
- operator: string;
175
- value: number;
176
- level: string;
177
- }>;
178
- diagnosticWorkflow: {
179
- trigger: {
180
- any_of: Array<{
181
- metric: string;
182
- operator: string;
183
- value: number;
184
- }>;
185
- };
186
- actions: Array<{
187
- type: string;
188
- metric?: string;
189
- dimensions?: string[];
190
- intent: string;
191
- }>;
192
- analysis_logic: string;
193
- };
194
- humanReadableExplanation: string;
195
- };
196
- }>;
197
- tablesDetails?: Array<{
198
- tableName: string;
199
- docType: string;
200
- docTypeEn: string;
201
- objTypeCode?: number;
202
- mainTable?: string;
203
- lineTable?: string;
204
- selectSql: string;
205
- columns: Array<{
206
- name: string;
207
- label: string;
208
- description?: string;
209
- type?: string;
210
- example?: string;
211
- } | null>;
212
- }>;
213
- };
214
- }
215
-
216
- /**
217
- * Semantic query response
218
- */
219
- interface SemanticQueryResponse {
220
- success: boolean;
221
- message: string;
222
- data?: {
223
- semanticModel: string;
224
- columns: string[];
225
- dataPoints: Array<{
226
- timestamp?: number;
227
- value: number;
228
- labels?: Record<string, string>;
229
- }>;
230
- metadata?: {
231
- rowCount?: number;
232
- columnCount?: number;
233
- };
234
- };
235
- }
236
-
237
- /**
238
- * Get all metrics server configs for a tenant
239
- */
240
- export async function getMetricsServerConfigList(
241
- request: FastifyRequest,
242
- reply: FastifyReply
243
- ): Promise<MetricsServerConfigListResponse> {
244
- const tenantId = getTenantId(request);
245
-
246
- try {
247
- const storeLattice = getStoreLattice("default", "metrics");
248
- const store: MetricsServerConfigStore = storeLattice.store;
249
-
250
- const configs = await store.getAllConfigs(tenantId);
251
-
252
- return {
253
- success: true,
254
- message: "Metrics server configurations retrieved successfully",
255
- data: {
256
- records: configs,
257
- total: configs.length,
258
- },
259
- };
260
- } catch (error) {
261
- console.error("Failed to get metrics server configs:", error);
262
- return {
263
- success: false,
264
- message: "Failed to retrieve metrics server configurations",
265
- data: {
266
- records: [],
267
- total: 0,
268
- },
269
- };
270
- }
271
- }
272
-
273
- /**
274
- * Get metrics server config by key
275
- */
276
- export async function getMetricsServerConfig(
277
- request: FastifyRequest,
278
- reply: FastifyReply
279
- ): Promise<MetricsServerConfigResponse> {
280
- const tenantId = getTenantId(request);
281
- const { key } = request.params as { key: string };
282
-
283
- try {
284
- const storeLattice = getStoreLattice("default", "metrics");
285
- const store: MetricsServerConfigStore = storeLattice.store;
286
-
287
- const config = await store.getConfigByKey(tenantId, key);
288
-
289
- if (!config) {
290
- return {
291
- success: false,
292
- message: "Metrics server configuration not found",
293
- };
294
- }
295
-
296
- return {
297
- success: true,
298
- message: "Metrics server configuration retrieved successfully",
299
- data: config,
300
- };
301
- } catch (error) {
302
- console.error("Failed to get metrics server config:", error);
303
- return {
304
- success: false,
305
- message: "Failed to retrieve metrics server configuration",
306
- };
307
- }
308
- }
309
-
310
- /**
311
- * Create new metrics server config
312
- */
313
- export async function createMetricsServerConfig(
314
- request: FastifyRequest,
315
- reply: FastifyReply
316
- ): Promise<MetricsServerConfigResponse> {
317
- const tenantId = getTenantId(request);
318
- const body = request.body as CreateMetricsServerConfigRequest & {
319
- id?: string;
320
- selectedDataSources?: string[];
321
- };
322
-
323
- try {
324
- const storeLattice = getStoreLattice("default", "metrics");
325
- const store: MetricsServerConfigStore = storeLattice.store;
326
-
327
- // Check if key already exists
328
- const existing = await store.getConfigByKey(tenantId, body.key);
329
- if (existing) {
330
- reply.code(409);
331
- return {
332
- success: false,
333
- message: "Metrics server configuration with this key already exists",
334
- };
335
- }
336
-
337
- if (body.config.type === "semantic" && !body.selectedDataSources) {
338
- reply.code(400);
339
- return {
340
- success: false,
341
- message: "selectedDataSources is required for semantic metrics servers",
342
- };
343
- }
344
-
345
- const id = body.id || randomUUID();
346
- const configData: CreateMetricsServerConfigRequest = {
347
- key: body.key,
348
- name: body.name,
349
- description: body.description,
350
- config: body.config.type === "semantic"
351
- ? {
352
- ...body.config,
353
- selectedDataSources: body.selectedDataSources || [],
354
- } as SemanticMetricsServerConfig
355
- : body.config,
356
- };
357
-
358
- const config = await store.createConfig(tenantId, id, configData);
359
-
360
- // Auto-register to MetricsServerManager
361
- try {
362
- metricsServerManager.registerServer(tenantId, config.key, config.config);
363
- } catch (error) {
364
- console.warn("Failed to auto-register metrics server:", error);
365
- }
366
-
367
- reply.code(201);
368
- return {
369
- success: true,
370
- message: "Metrics server configuration created successfully",
371
- data: config,
372
- };
373
- } catch (error) {
374
- console.error("Failed to create metrics server config:", error);
375
- return {
376
- success: false,
377
- message: "Failed to create metrics server configuration",
378
- };
379
- }
380
- }
381
-
382
- /**
383
- * Update metrics server config
384
- */
385
- export async function updateMetricsServerConfig(
386
- request: FastifyRequest,
387
- reply: FastifyReply
388
- ): Promise<MetricsServerConfigResponse> {
389
- const tenantId = getTenantId(request);
390
- const { key } = request.params as { key: string };
391
- const updates = request.body as Partial<UpdateMetricsServerConfigRequest> & {
392
- selectedDataSources?: string[];
393
- };
394
-
395
- try {
396
- const storeLattice = getStoreLattice("default", "metrics");
397
- const store: MetricsServerConfigStore = storeLattice.store;
398
-
399
- const existing = await store.getConfigByKey(tenantId, key);
400
- if (!existing) {
401
- reply.code(404);
402
- return {
403
- success: false,
404
- message: "Metrics server configuration not found",
405
- };
406
- }
407
-
408
- const isSemantic = updates.config?.type === "semantic" ||
409
- (existing.config.type === "semantic" && !updates.config?.type);
410
-
411
- if (isSemantic && updates.selectedDataSources !== undefined) {
412
- updates.config = {
413
- ...existing.config,
414
- ...updates.config,
415
- type: "semantic",
416
- selectedDataSources: updates.selectedDataSources,
417
- } as SemanticMetricsServerConfig;
418
- }
419
-
420
- const updated = await store.updateConfig(tenantId, existing.id, updates);
421
-
422
- if (!updated) {
423
- return {
424
- success: false,
425
- message: "Failed to update metrics server configuration",
426
- };
427
- }
428
-
429
- if (updates.config) {
430
- try {
431
- metricsServerManager.registerServer(tenantId, updated.key, updated.config);
432
- } catch (error) {
433
- console.warn("Failed to re-register metrics server:", error);
434
- }
435
- }
436
-
437
- return {
438
- success: true,
439
- message: "Metrics server configuration updated successfully",
440
- data: updated,
441
- };
442
- } catch (error) {
443
- console.error("Failed to update metrics server config:", error);
444
- return {
445
- success: false,
446
- message: "Failed to update metrics server configuration",
447
- };
448
- }
449
- }
450
-
451
- /**
452
- * Delete metrics server config by key or id
453
- */
454
- export async function deleteMetricsServerConfig(
455
- request: FastifyRequest,
456
- reply: FastifyReply
457
- ): Promise<MetricsServerConfigResponse> {
458
- const tenantId = getTenantId(request);
459
- const { keyOrId } = request.params as { keyOrId: string };
460
-
461
- try {
462
- const storeLattice = getStoreLattice("default", "metrics");
463
- const store: MetricsServerConfigStore = storeLattice.store;
464
-
465
- // Try to find by key first, then by id
466
- let config = await store.getConfigByKey(tenantId, keyOrId);
467
- let configKey = keyOrId;
468
-
469
- if (!config) {
470
- // Try to find by id
471
- config = await store.getConfigById(tenantId, keyOrId);
472
- if (config) {
473
- configKey = config.key;
474
- }
475
- }
476
-
477
- if (!config) {
478
- reply.code(404);
479
- return {
480
- success: false,
481
- message: "Metrics server configuration not found",
482
- };
483
- }
484
-
485
- const deleted = await store.deleteConfig(tenantId, config.id);
486
-
487
- if (!deleted) {
488
- return {
489
- success: false,
490
- message: "Failed to delete metrics server configuration",
491
- };
492
- }
493
-
494
- // Remove from MetricsServerManager
495
- try {
496
- if (metricsServerManager.hasServer(tenantId, configKey)) {
497
- metricsServerManager.removeServer(tenantId, configKey);
498
- }
499
- } catch (error) {
500
- console.warn("Failed to remove from MetricsServerManager:", error);
501
- }
502
-
503
- return {
504
- success: true,
505
- message: "Metrics server configuration deleted successfully",
506
- };
507
- } catch (error) {
508
- console.error("Failed to delete metrics server config:", error);
509
- return {
510
- success: false,
511
- message: "Failed to delete metrics server configuration",
512
- };
513
- }
514
- }
515
-
516
- /**
517
- * Test metrics server connection
518
- */
519
- export async function testMetricsServerConnection(
520
- request: FastifyRequest,
521
- reply: FastifyReply
522
- ): Promise<TestConnectionResponse> {
523
- const tenantId = getTenantId(request);
524
- const { key } = request.params as { key: string };
525
-
526
- try {
527
- const storeLattice = getStoreLattice("default", "metrics");
528
- const store: MetricsServerConfigStore = storeLattice.store;
529
-
530
- const config = await store.getConfigByKey(tenantId, key);
531
- if (!config) {
532
- reply.code(404);
533
- return {
534
- success: false,
535
- message: "Metrics server configuration not found",
536
- };
537
- }
538
-
539
- // Register temporarily for testing
540
- const testKey = `__test_${key}_${Date.now()}`;
541
- metricsServerManager.registerServer(tenantId, testKey, config.config);
542
-
543
- try {
544
- const client = await metricsServerManager.getClient(tenantId, testKey);
545
- const result = await client.testConnection();
546
-
547
- // Cleanup
548
- metricsServerManager.removeServer(tenantId, testKey);
549
-
550
- return {
551
- success: true,
552
- message: result.connected ? "Connection test successful" : "Connection test failed",
553
- data: result,
554
- };
555
- } catch (error) {
556
- // Cleanup on error
557
- try {
558
- metricsServerManager.removeServer(tenantId, testKey);
559
- } catch { /* cleanup error, ignore */ }
560
-
561
- return {
562
- success: true,
563
- message: "Connection test failed",
564
- data: {
565
- connected: false,
566
- error: error instanceof Error ? error.message : "Unknown error",
567
- },
568
- };
569
- }
570
- } catch (error) {
571
- console.error("Failed to test metrics server connection:", error);
572
- return {
573
- success: false,
574
- message: "Failed to test metrics server connection",
575
- data: {
576
- connected: false,
577
- error: error instanceof Error ? error.message : "Unknown error",
578
- },
579
- };
580
- }
581
- }
582
-
583
- /**
584
- * List available metrics from a server
585
- */
586
- export async function listAvailableMetrics(
587
- request: FastifyRequest,
588
- reply: FastifyReply
589
- ): Promise<ListMetricsResponse> {
590
- const tenantId = getTenantId(request);
591
- const { key } = request.params as { key: string };
592
-
593
- try {
594
- const storeLattice = getStoreLattice("default", "metrics");
595
- const store: MetricsServerConfigStore = storeLattice.store;
596
-
597
- const config = await store.getConfigByKey(tenantId, key);
598
- if (!config) {
599
- reply.code(404);
600
- return {
601
- success: false,
602
- message: "Metrics server configuration not found",
603
- };
604
- }
605
-
606
- // Ensure server is registered
607
- if (!metricsServerManager.hasServer(tenantId, key)) {
608
- metricsServerManager.registerServer(tenantId, key, config.config);
609
- }
610
-
611
- const client = await metricsServerManager.getClient(tenantId, key);
612
- const metrics = await client.listMetrics();
613
-
614
- return {
615
- success: true,
616
- message: "Metrics retrieved successfully",
617
- data: {
618
- metrics: metrics.map(m => ({
619
- name: m.name,
620
- type: m.type,
621
- description: m.description,
622
- })),
623
- },
624
- };
625
- } catch (error) {
626
- console.error("Failed to list metrics:", error);
627
- return {
628
- success: false,
629
- message: "Failed to retrieve metrics",
630
- };
631
- }
632
- }
633
-
634
- /**
635
- * Query metric data from a server
636
- */
637
- export async function queryMetricsData(
638
- request: FastifyRequest,
639
- reply: FastifyReply
640
- ): Promise<QueryMetricDataResponse> {
641
- const tenantId = getTenantId(request);
642
- const { key } = request.params as { key: string };
643
- const { metricName, startTime, endTime, step, labels } = request.body as {
644
- metricName: string;
645
- startTime?: number;
646
- endTime?: number;
647
- step?: number;
648
- labels?: Record<string, string>;
649
- };
650
-
651
- try {
652
- const storeLattice = getStoreLattice("default", "metrics");
653
- const store: MetricsServerConfigStore = storeLattice.store;
654
-
655
- const config = await store.getConfigByKey(tenantId, key);
656
- if (!config) {
657
- reply.code(404);
658
- return {
659
- success: false,
660
- message: "Metrics server configuration not found",
661
- };
662
- }
663
-
664
- if (!metricName) {
665
- reply.code(400);
666
- return {
667
- success: false,
668
- message: "metricName is required",
669
- };
670
- }
671
-
672
- // Ensure server is registered
673
- if (!metricsServerManager.hasServer(tenantId, key)) {
674
- metricsServerManager.registerServer(tenantId, key, config.config);
675
- }
676
-
677
- const client = await metricsServerManager.getClient(tenantId, key);
678
- const result = await client.queryMetricData(metricName, {
679
- startTime,
680
- endTime,
681
- step,
682
- labels,
683
- });
684
-
685
- return {
686
- success: true,
687
- message: "Metric data retrieved successfully",
688
- data: {
689
- metricName: result.metricName,
690
- dataPoints: result.dataPoints,
691
- },
692
- };
693
- } catch (error) {
694
- console.error("Failed to query metric data:", error);
695
- return {
696
- success: false,
697
- message: "Failed to query metric data",
698
- };
699
- }
700
- }
701
-
702
- /**
703
- * Get data sources for a semantic metrics server
704
- * GET /api/metrics-configs/:key/datasources
705
- */
706
- export async function getDataSources(
707
- request: FastifyRequest,
708
- reply: FastifyReply
709
- ): Promise<DataSourcesResponse> {
710
- const tenantId = getTenantId(request);
711
- const { key } = request.params as { key: string };
712
-
713
- try {
714
- const storeLattice = getStoreLattice("default", "metrics");
715
- const store: MetricsServerConfigStore = storeLattice.store;
716
-
717
- const config = await store.getConfigByKey(tenantId, key);
718
- if (!config) {
719
- reply.code(404);
720
- return {
721
- success: false,
722
- message: "Metrics server configuration not found",
723
- };
724
- }
725
-
726
- if (config.config.type !== "semantic") {
727
- reply.code(400);
728
- return {
729
- success: false,
730
- message: "This endpoint is only available for semantic metrics servers",
731
- };
732
- }
733
-
734
- const semanticConfig = config.config as SemanticMetricsServerConfig;
735
-
736
- const client = new SemanticMetricsClient(semanticConfig);
737
- const allDatasources = await client.getDataSources();
738
-
739
- // Filter datasources by selectedDataSources if configured
740
- const selectedIds = semanticConfig.selectedDataSources || [];
741
- const filteredDatasources = selectedIds.length > 0
742
- ? allDatasources.filter(ds => selectedIds.includes(String(ds.id)))
743
- : allDatasources;
744
-
745
- return {
746
- success: true,
747
- message: "Data sources retrieved successfully",
748
- data: {
749
- datasources: filteredDatasources,
750
- },
751
- };
752
- } catch (error) {
753
- console.error("Failed to get data sources:", error);
754
- return {
755
- success: false,
756
- message: "Failed to retrieve data sources",
757
- };
758
- }
759
- }
760
-
761
- /**
762
- * Get metrics for a specific data source
763
- * GET /api/metrics-configs/:key/datasources/:datasourceId/metrics
764
- */
765
- export async function getDatasourceMetrics(
766
- request: FastifyRequest,
767
- reply: FastifyReply
768
- ): Promise<DatasourceMetricsResponse> {
769
- const tenantId = getTenantId(request);
770
- const { key, datasourceId } = request.params as { key: string; datasourceId: string };
771
-
772
- try {
773
- const storeLattice = getStoreLattice("default", "metrics");
774
- const store: MetricsServerConfigStore = storeLattice.store;
775
-
776
- const config = await store.getConfigByKey(tenantId, key);
777
- if (!config) {
778
- reply.code(404);
779
- return {
780
- success: false,
781
- message: "Metrics server configuration not found",
782
- };
783
- }
784
-
785
- if (config.config.type !== "semantic") {
786
- reply.code(400);
787
- return {
788
- success: false,
789
- message: "This endpoint is only available for semantic metrics servers",
790
- };
791
- }
792
-
793
- const semanticConfig = config.config as SemanticMetricsServerConfig;
794
-
795
- const client = new SemanticMetricsClient(semanticConfig);
796
- const metrics = await client.getDatasourceMetrics(datasourceId);
797
-
798
- return {
799
- success: true,
800
- message: "Datasource metrics retrieved successfully",
801
- data: metrics,
802
- };
803
- } catch (error) {
804
- console.error("Failed to get datasource metrics:", error);
805
- return {
806
- success: false,
807
- message: "Failed to retrieve datasource metrics",
808
- };
809
- }
810
- }
811
-
812
- /**
813
- * Query semantic metrics data
814
- * POST /api/metrics-configs/:key/semantic-query
815
- */
816
- export async function querySemanticMetrics(
817
- request: FastifyRequest,
818
- reply: FastifyReply
819
- ): Promise<SemanticQueryResponse> {
820
- const tenantId = getTenantId(request);
821
- const { key } = request.params as { key: string };
822
- const body = request.body as SemanticMetricsQueryRequest;
823
-
824
- try {
825
- const storeLattice = getStoreLattice("default", "metrics");
826
- const store: MetricsServerConfigStore = storeLattice.store;
827
-
828
- const config = await store.getConfigByKey(tenantId, key);
829
- if (!config) {
830
- reply.code(404);
831
- return {
832
- success: false,
833
- message: "Metrics server configuration not found",
834
- };
835
- }
836
-
837
- if (config.config.type !== "semantic") {
838
- reply.code(400);
839
- return {
840
- success: false,
841
- message: "This endpoint is only available for semantic metrics servers",
842
- };
843
- }
844
-
845
- if (!body.datasourceId || !body.metrics || body.metrics.length === 0) {
846
- reply.code(400);
847
- return {
848
- success: false,
849
- message: "datasourceId and metrics array are required",
850
- };
851
- }
852
-
853
- const semanticConfig = config.config as SemanticMetricsServerConfig;
854
-
855
- const client = new SemanticMetricsClient(semanticConfig);
856
- const result = await client.semanticQuery(body);
857
-
858
- // Transform SemanticMetricsQueryResponse to response format
859
- // The response contains columns and rows arrays
860
- const columnNames = result.columns.map(col => col.name);
861
- const allDataPoints: Array<{
862
- timestamp?: number;
863
- value: number;
864
- labels?: Record<string, string>;
865
- }> = [];
866
-
867
- // Find timestamp column and value column indices
868
- const timestampColIdx = columnNames.findIndex(col =>
869
- col.toLowerCase().includes('date') || col.toLowerCase().includes('time')
870
- );
871
- const valueColIdx = columnNames.findIndex(col =>
872
- col.toLowerCase().includes('value') || col.toLowerCase().includes('rate') || col.toLowerCase().includes('amt')
873
- );
874
-
875
- for (const row of result.rows ?? []) {
876
- const timestamp = timestampColIdx >= 0 ? row[timestampColIdx] : undefined;
877
- const value = valueColIdx >= 0 ? row[valueColIdx] : row[row.length - 1];
878
-
879
- allDataPoints.push({
880
- timestamp: timestamp ? new Date(String(timestamp)).getTime() : undefined,
881
- value: typeof value === 'number' ? value : Number(value) || 0,
882
- labels: Object.fromEntries(
883
- columnNames.map((col, idx) => [col, String(row[idx] ?? '')])
884
- ),
885
- });
886
- }
887
-
888
- return {
889
- success: true,
890
- message: "Semantic query executed successfully",
891
- data: {
892
- semanticModel: result.semanticModel,
893
- columns: columnNames,
894
- dataPoints: allDataPoints,
895
- metadata: {
896
- rowCount: result.rows?.length ?? 0,
897
- columnCount: result.columns.length,
898
- },
899
- },
900
- };
901
- } catch (error) {
902
- console.error("Failed to query semantic metrics:", error);
903
- return {
904
- success: false,
905
- message: "Failed to query semantic metrics",
906
- };
907
- }
908
- }
909
-
910
- /**
911
- * Test datasources endpoint without saving config
912
- * Used for multi-step configuration flow
913
- * POST /api/metrics-configs/test-datasources
914
- */
915
- export async function testSemanticDataSources(
916
- request: FastifyRequest,
917
- reply: FastifyReply
918
- ): Promise<DataSourcesResponse> {
919
- const body = request.body as {
920
- serverUrl: string;
921
- apiKey?: string;
922
- username?: string;
923
- password?: string;
924
- headers?: Record<string, string>;
925
- };
926
-
927
- try {
928
- if (!body.serverUrl) {
929
- reply.code(400);
930
- return {
931
- success: false,
932
- message: "serverUrl is required",
933
- };
934
- }
935
-
936
- const testConfig: SemanticMetricsServerConfig = {
937
- type: "semantic",
938
- serverUrl: body.serverUrl,
939
- apiKey: body.apiKey,
940
- username: body.username,
941
- password: body.password,
942
- headers: body.headers,
943
- };
944
-
945
- const client = new SemanticMetricsClient(testConfig);
946
-
947
- const datasources = await client.getDataSources();
948
-
949
- return {
950
- success: true,
951
- message: "Data sources retrieved successfully",
952
- data: {
953
- datasources,
954
- },
955
- };
956
- } catch (error) {
957
- console.error("Failed to test datasources:", error);
958
- return {
959
- success: false,
960
- message: `Failed to retrieve data sources: ${error instanceof Error ? error.message : String(error)}`,
961
- };
962
- }
963
- }
964
-
965
- /**
966
- * Test datasource metrics endpoint without saving config
967
- * Used for multi-step configuration flow
968
- * POST /api/metrics-configs/test-datasources/:datasourceId/metrics
969
- */
970
- export async function testDatasourceMetrics(
971
- request: FastifyRequest,
972
- reply: FastifyReply
973
- ): Promise<DatasourceMetricsResponse> {
974
- const { datasourceId } = request.params as { datasourceId: string };
975
- const body = request.body as {
976
- serverUrl: string;
977
- apiKey?: string;
978
- username?: string;
979
- password?: string;
980
- headers?: Record<string, string>;
981
- };
982
-
983
- try {
984
- if (!body.serverUrl) {
985
- reply.code(400);
986
- return {
987
- success: false,
988
- message: "serverUrl is required",
989
- };
990
- }
991
-
992
- const testConfig: SemanticMetricsServerConfig = {
993
- type: "semantic",
994
- serverUrl: body.serverUrl,
995
- apiKey: body.apiKey,
996
- username: body.username,
997
- password: body.password,
998
- headers: body.headers,
999
- };
1000
-
1001
- const client = new SemanticMetricsClient(testConfig);
1002
- const metrics = await client.getDatasourceMetrics(datasourceId);
1003
-
1004
- return {
1005
- success: true,
1006
- message: "Datasource metrics retrieved successfully",
1007
- data: metrics,
1008
- };
1009
- } catch (error) {
1010
- console.error("Failed to test datasource metrics:", error);
1011
- return {
1012
- success: false,
1013
- message: `Failed to retrieve datasource metrics: ${error instanceof Error ? error.message : String(error)}`,
1014
- };
1015
- }
1016
- }
1017
-
1018
- /**
1019
- * Register metrics server config routes
1020
- */
1021
- export function registerMetricsServerConfigRoutes(app: any): void {
1022
- // Get all configs
1023
- app.get("/api/metrics-configs", getMetricsServerConfigList);
1024
-
1025
- // Get config by key
1026
- app.get("/api/metrics-configs/:key", getMetricsServerConfig);
1027
-
1028
- // Create config
1029
- app.post("/api/metrics-configs", createMetricsServerConfig);
1030
-
1031
- // Update config
1032
- app.put("/api/metrics-configs/:key", updateMetricsServerConfig);
1033
-
1034
- // Delete config by key or id
1035
- app.delete("/api/metrics-configs/:keyOrId", deleteMetricsServerConfig);
1036
-
1037
- // Test connection
1038
- app.post("/api/metrics-configs/:key/test", testMetricsServerConnection);
1039
-
1040
- // List available metrics
1041
- app.get("/api/metrics-configs/:key/metrics", listAvailableMetrics);
1042
-
1043
- // Query metric data
1044
- app.post("/api/metrics-configs/:key/query", queryMetricsData);
1045
-
1046
- // Semantic-specific routes
1047
- // Get data sources for a semantic server
1048
- app.get("/api/metrics-configs/:key/datasources", getDataSources);
1049
-
1050
- // Get metrics meta for a specific datasource
1051
- app.get("/api/metrics-configs/:key/datasources/:datasourceId/meta", getDatasourceMetrics);
1052
-
1053
- // Query semantic metrics data
1054
- app.post("/api/metrics-configs/:key/semantic-query", querySemanticMetrics);
1055
-
1056
- // Test datasources without saving config (for multi-step config flow)
1057
- app.post("/api/metrics-configs/test-datasources", testSemanticDataSources);
1058
-
1059
- // Test datasource metrics meta without saving config (for multi-step config flow)
1060
- app.post("/api/metrics-configs/test-datasources/:datasourceId/meta", testDatasourceMetrics);
1061
- }