taurusdb-core 0.1.0

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 (170) hide show
  1. package/README.md +21 -0
  2. package/dist/auth/secret-resolver.d.ts +16 -0
  3. package/dist/auth/secret-resolver.js +64 -0
  4. package/dist/auth/sql-profile-loader/env-source.d.ts +3 -0
  5. package/dist/auth/sql-profile-loader/env-source.js +94 -0
  6. package/dist/auth/sql-profile-loader/file-source.d.ts +6 -0
  7. package/dist/auth/sql-profile-loader/file-source.js +40 -0
  8. package/dist/auth/sql-profile-loader/loader.d.ts +16 -0
  9. package/dist/auth/sql-profile-loader/loader.js +81 -0
  10. package/dist/auth/sql-profile-loader/parsing.d.ts +14 -0
  11. package/dist/auth/sql-profile-loader/parsing.js +216 -0
  12. package/dist/auth/sql-profile-loader/runtime-override.d.ts +14 -0
  13. package/dist/auth/sql-profile-loader/runtime-override.js +52 -0
  14. package/dist/auth/sql-profile-loader/types.d.ts +64 -0
  15. package/dist/auth/sql-profile-loader/types.js +1 -0
  16. package/dist/auth/sql-profile-loader.d.ts +4 -0
  17. package/dist/auth/sql-profile-loader.js +3 -0
  18. package/dist/capability/feature-matrix.d.ts +5 -0
  19. package/dist/capability/feature-matrix.js +237 -0
  20. package/dist/capability/probe.d.ts +19 -0
  21. package/dist/capability/probe.js +139 -0
  22. package/dist/capability/types.d.ts +49 -0
  23. package/dist/capability/types.js +16 -0
  24. package/dist/capability/version.d.ts +3 -0
  25. package/dist/capability/version.js +47 -0
  26. package/dist/cloud/auth.d.ts +26 -0
  27. package/dist/cloud/auth.js +198 -0
  28. package/dist/cloud/instances.d.ts +46 -0
  29. package/dist/cloud/instances.js +224 -0
  30. package/dist/config/env.d.ts +1 -0
  31. package/dist/config/env.js +194 -0
  32. package/dist/config/index.d.ts +6 -0
  33. package/dist/config/index.js +21 -0
  34. package/dist/config/redaction.d.ts +2 -0
  35. package/dist/config/redaction.js +19 -0
  36. package/dist/config/schema.d.ts +417 -0
  37. package/dist/config/schema.js +100 -0
  38. package/dist/context/datasource-resolver.d.ts +19 -0
  39. package/dist/context/datasource-resolver.js +71 -0
  40. package/dist/context/session-context.d.ts +26 -0
  41. package/dist/context/session-context.js +1 -0
  42. package/dist/diagnostics/metrics-source.d.ts +65 -0
  43. package/dist/diagnostics/metrics-source.js +280 -0
  44. package/dist/diagnostics/slow-sql-source/das-source.d.ts +43 -0
  45. package/dist/diagnostics/slow-sql-source/das-source.js +170 -0
  46. package/dist/diagnostics/slow-sql-source/factory.d.ts +5 -0
  47. package/dist/diagnostics/slow-sql-source/factory.js +87 -0
  48. package/dist/diagnostics/slow-sql-source/parsers.d.ts +7 -0
  49. package/dist/diagnostics/slow-sql-source/parsers.js +125 -0
  50. package/dist/diagnostics/slow-sql-source/taurus-api-source.d.ts +42 -0
  51. package/dist/diagnostics/slow-sql-source/taurus-api-source.js +149 -0
  52. package/dist/diagnostics/slow-sql-source/types.d.ts +40 -0
  53. package/dist/diagnostics/slow-sql-source/types.js +1 -0
  54. package/dist/diagnostics/slow-sql-source/utils.d.ts +20 -0
  55. package/dist/diagnostics/slow-sql-source/utils.js +170 -0
  56. package/dist/diagnostics/slow-sql-source.d.ts +4 -0
  57. package/dist/diagnostics/slow-sql-source.js +3 -0
  58. package/dist/diagnostics/types.d.ts +189 -0
  59. package/dist/diagnostics/types.js +39 -0
  60. package/dist/engine/data-access/locks.d.ts +8 -0
  61. package/dist/engine/data-access/locks.js +146 -0
  62. package/dist/engine/data-access/processlist.d.ts +4 -0
  63. package/dist/engine/data-access/processlist.js +56 -0
  64. package/dist/engine/data-access/statements.d.ts +10 -0
  65. package/dist/engine/data-access/statements.js +203 -0
  66. package/dist/engine/data-access/storage.d.ts +6 -0
  67. package/dist/engine/data-access/storage.js +96 -0
  68. package/dist/engine/data-access.d.ts +4 -0
  69. package/dist/engine/data-access.js +4 -0
  70. package/dist/engine/diagnostics.d.ts +7 -0
  71. package/dist/engine/diagnostics.js +7 -0
  72. package/dist/engine/helper-modules/diagnostics.d.ts +57 -0
  73. package/dist/engine/helper-modules/diagnostics.js +322 -0
  74. package/dist/engine/helper-modules/parsers.d.ts +13 -0
  75. package/dist/engine/helper-modules/parsers.js +283 -0
  76. package/dist/engine/helper-modules/sql.d.ts +12 -0
  77. package/dist/engine/helper-modules/sql.js +119 -0
  78. package/dist/engine/helper-modules/types.d.ts +103 -0
  79. package/dist/engine/helper-modules/types.js +1 -0
  80. package/dist/engine/helpers.d.ts +4 -0
  81. package/dist/engine/helpers.js +4 -0
  82. package/dist/engine/runtime.d.ts +20 -0
  83. package/dist/engine/runtime.js +385 -0
  84. package/dist/engine/types.d.ts +125 -0
  85. package/dist/engine/types.js +1 -0
  86. package/dist/engine/workflows/connection-spike.d.ts +4 -0
  87. package/dist/engine/workflows/connection-spike.js +316 -0
  88. package/dist/engine/workflows/db-hotspot.d.ts +4 -0
  89. package/dist/engine/workflows/db-hotspot.js +182 -0
  90. package/dist/engine/workflows/lock-contention-helpers/entities.d.ts +9 -0
  91. package/dist/engine/workflows/lock-contention-helpers/entities.js +58 -0
  92. package/dist/engine/workflows/lock-contention-helpers/no-match.d.ts +3 -0
  93. package/dist/engine/workflows/lock-contention-helpers/no-match.js +65 -0
  94. package/dist/engine/workflows/lock-contention-helpers/report.d.ts +21 -0
  95. package/dist/engine/workflows/lock-contention-helpers/report.js +104 -0
  96. package/dist/engine/workflows/lock-contention-helpers/root-cause.d.ts +4 -0
  97. package/dist/engine/workflows/lock-contention-helpers/root-cause.js +79 -0
  98. package/dist/engine/workflows/lock-contention-helpers/signals.d.ts +22 -0
  99. package/dist/engine/workflows/lock-contention-helpers/signals.js +34 -0
  100. package/dist/engine/workflows/lock-contention-helpers.d.ts +5 -0
  101. package/dist/engine/workflows/lock-contention-helpers.js +5 -0
  102. package/dist/engine/workflows/lock-contention.d.ts +4 -0
  103. package/dist/engine/workflows/lock-contention.js +67 -0
  104. package/dist/engine/workflows/service-latency.d.ts +4 -0
  105. package/dist/engine/workflows/service-latency.js +262 -0
  106. package/dist/engine/workflows/slow-query-helpers.d.ts +41 -0
  107. package/dist/engine/workflows/slow-query-helpers.js +253 -0
  108. package/dist/engine/workflows/slow-query.d.ts +4 -0
  109. package/dist/engine/workflows/slow-query.js +156 -0
  110. package/dist/engine/workflows/storage-pressure-helpers.d.ts +12 -0
  111. package/dist/engine/workflows/storage-pressure-helpers.js +281 -0
  112. package/dist/engine/workflows/storage-pressure.d.ts +4 -0
  113. package/dist/engine/workflows/storage-pressure.js +27 -0
  114. package/dist/engine/workflows/top-slow-sql.d.ts +4 -0
  115. package/dist/engine/workflows/top-slow-sql.js +222 -0
  116. package/dist/engine.d.ts +77 -0
  117. package/dist/engine.js +240 -0
  118. package/dist/executor/adapters/mysql.d.ts +2 -0
  119. package/dist/executor/adapters/mysql.js +114 -0
  120. package/dist/executor/connection-pool.d.ts +105 -0
  121. package/dist/executor/connection-pool.js +236 -0
  122. package/dist/executor/explain.d.ts +5 -0
  123. package/dist/executor/explain.js +119 -0
  124. package/dist/executor/query-tracker.d.ts +45 -0
  125. package/dist/executor/query-tracker.js +83 -0
  126. package/dist/executor/result-normalizer.d.ts +6 -0
  127. package/dist/executor/result-normalizer.js +47 -0
  128. package/dist/executor/sql-executor.d.ts +32 -0
  129. package/dist/executor/sql-executor.js +250 -0
  130. package/dist/executor/types.d.ts +70 -0
  131. package/dist/executor/types.js +1 -0
  132. package/dist/index.d.ts +40 -0
  133. package/dist/index.js +21 -0
  134. package/dist/safety/confirmation-store.d.ts +44 -0
  135. package/dist/safety/confirmation-store.js +130 -0
  136. package/dist/safety/guardrail.d.ts +39 -0
  137. package/dist/safety/guardrail.js +99 -0
  138. package/dist/safety/parser/adapter.d.ts +10 -0
  139. package/dist/safety/parser/adapter.js +72 -0
  140. package/dist/safety/parser/ast-utils.d.ts +10 -0
  141. package/dist/safety/parser/ast-utils.js +167 -0
  142. package/dist/safety/parser/features.d.ts +12 -0
  143. package/dist/safety/parser/features.js +113 -0
  144. package/dist/safety/parser/index.d.ts +2 -0
  145. package/dist/safety/parser/index.js +1 -0
  146. package/dist/safety/parser/types.d.ts +76 -0
  147. package/dist/safety/parser/types.js +1 -0
  148. package/dist/safety/redaction.d.ts +34 -0
  149. package/dist/safety/redaction.js +186 -0
  150. package/dist/safety/sql-classifier.d.ts +19 -0
  151. package/dist/safety/sql-classifier.js +43 -0
  152. package/dist/safety/sql-validator.d.ts +19 -0
  153. package/dist/safety/sql-validator.js +143 -0
  154. package/dist/schema/adapters/mysql.d.ts +16 -0
  155. package/dist/schema/adapters/mysql.js +287 -0
  156. package/dist/schema/introspector.d.ts +70 -0
  157. package/dist/schema/introspector.js +40 -0
  158. package/dist/taurus/flashback.d.ts +36 -0
  159. package/dist/taurus/flashback.js +149 -0
  160. package/dist/taurus/recycle-bin.d.ts +14 -0
  161. package/dist/taurus/recycle-bin.js +61 -0
  162. package/dist/utils/formatter.d.ts +70 -0
  163. package/dist/utils/formatter.js +60 -0
  164. package/dist/utils/hash.d.ts +2 -0
  165. package/dist/utils/hash.js +247 -0
  166. package/dist/utils/id.d.ts +2 -0
  167. package/dist/utils/id.js +11 -0
  168. package/dist/utils/logger.d.ts +9 -0
  169. package/dist/utils/logger.js +39 -0
  170. package/package.json +46 -0
@@ -0,0 +1,125 @@
1
+ import { parseDurationMs, readNumber, readString, secondsToMs } from "./utils.js";
2
+ export function pickArrayCandidate(payload) {
3
+ if (!payload || typeof payload !== "object") {
4
+ return [];
5
+ }
6
+ const record = payload;
7
+ for (const key of [
8
+ "slow_log_list",
9
+ "slow_log_statistics",
10
+ "slow_log_statistic_list",
11
+ "items",
12
+ "records",
13
+ ]) {
14
+ const value = record[key];
15
+ if (Array.isArray(value)) {
16
+ return value.filter((item) => item !== null && typeof item === "object" && !Array.isArray(item));
17
+ }
18
+ }
19
+ return [];
20
+ }
21
+ export function parseStatisticsCandidate(item, rawRef) {
22
+ const sql = readString(item.query_sample) ?? readString(item.sql_statement);
23
+ if (!sql) {
24
+ return undefined;
25
+ }
26
+ return {
27
+ sql,
28
+ database: readString(item.database),
29
+ user: readString(item.users) ?? readString(item.user),
30
+ clientIp: readString(item.client_ip),
31
+ startTime: readString(item.start_at) ?? readString(item.time),
32
+ execCount: readNumber(item.count),
33
+ avgLatencyMs: parseDurationMs(item.execute_time) ?? parseDurationMs(item.avg_query_time),
34
+ avgLockTimeMs: parseDurationMs(item.lock_time),
35
+ avgRowsExamined: readNumber(item.rows_examined),
36
+ rowsSent: readNumber(item.rows_sent),
37
+ rawRef,
38
+ };
39
+ }
40
+ export function parseDetailCandidate(item, rawRef) {
41
+ const sql = readString(item.query_sample) ?? readString(item.sql_statement);
42
+ if (!sql) {
43
+ return undefined;
44
+ }
45
+ return {
46
+ sql,
47
+ database: readString(item.database),
48
+ user: readString(item.user),
49
+ clientIp: readString(item.client_ip),
50
+ startTime: readString(item.start_at) ?? readString(item.time),
51
+ execCount: 1,
52
+ avgLatencyMs: parseDurationMs(item.query_time) ?? parseDurationMs(item.execute_time),
53
+ avgLockTimeMs: parseDurationMs(item.lock_time),
54
+ avgRowsExamined: readNumber(item.rows_examined),
55
+ rowsSent: readNumber(item.rows_sent),
56
+ rawRef,
57
+ };
58
+ }
59
+ export function parseDasSlowLogCandidate(item, rawRef) {
60
+ const sql = readString(item.sql) ??
61
+ readString(item.query) ??
62
+ readString(item.sql_statement) ??
63
+ readString(item.template);
64
+ if (!sql) {
65
+ return undefined;
66
+ }
67
+ return {
68
+ sql,
69
+ database: readString(item.database) ??
70
+ readString(item.db_name) ??
71
+ readString(item.databases),
72
+ user: readString(item.users) ?? readString(item.user),
73
+ clientIp: readString(item.client_ip),
74
+ startTime: readString(item.start_at) ??
75
+ readString(item.time) ??
76
+ readString(item.timestamp),
77
+ execCount: readNumber(item.count) ?? 1,
78
+ avgLatencyMs: secondsToMs(item.query_time) ??
79
+ parseDurationMs(item.query_time_ms) ??
80
+ secondsToMs(item.avg_query_time),
81
+ avgLockTimeMs: secondsToMs(item.lock_time) ?? parseDurationMs(item.lock_time_ms),
82
+ avgRowsExamined: readNumber(item.rows_examined),
83
+ rowsSent: readNumber(item.rows_sent),
84
+ rawRef,
85
+ };
86
+ }
87
+ export function parseDasSqlStatementCandidate(item, rawRef) {
88
+ const sql = readString(item.sql) ??
89
+ readString(item.sql_statement) ??
90
+ readString(item.query);
91
+ if (!sql) {
92
+ return undefined;
93
+ }
94
+ return {
95
+ sql,
96
+ database: readString(item.database) ??
97
+ readString(item.db_name) ??
98
+ readString(item.schema_name),
99
+ user: readString(item.user) ?? readString(item.users),
100
+ clientIp: readString(item.client_ip),
101
+ startTime: readString(item.start_at) ??
102
+ readString(item.time) ??
103
+ readString(item.timestamp),
104
+ execCount: 1,
105
+ avgLatencyMs: parseDurationMs(item.query_time) ??
106
+ secondsToMs(item.query_time_second) ??
107
+ parseDurationMs(item.duration),
108
+ avgLockTimeMs: parseDurationMs(item.lock_time) ?? secondsToMs(item.lock_time_second),
109
+ avgRowsExamined: readNumber(item.rows_examined),
110
+ rowsSent: readNumber(item.rows_sent),
111
+ rawRef,
112
+ };
113
+ }
114
+ export function pickDasTopSlowArrays(payload) {
115
+ const arrays = [
116
+ payload.top_execute_slow_logs,
117
+ payload.top_avg_query_time_slow_logs,
118
+ payload.top_max_query_time_slow_logs,
119
+ payload.top_returned_rows_slow_logs,
120
+ payload.top_rows_examined_slow_logs,
121
+ ];
122
+ return arrays.flatMap((value) => Array.isArray(value)
123
+ ? value.filter((item) => item !== null && typeof item === "object" && !Array.isArray(item))
124
+ : []);
125
+ }
@@ -0,0 +1,42 @@
1
+ import type { SessionContext } from "../../context/session-context.js";
2
+ import type { FindTopSlowSqlInput } from "../types.js";
3
+ import type { ExternalSlowSqlSample, ResolveSlowSqlInput, SlowSqlSource } from "./types.js";
4
+ type TaurusApiSlowSqlSourceOptions = {
5
+ endpoint: string;
6
+ projectId: string;
7
+ instanceId: string;
8
+ nodeId: string;
9
+ authToken?: string;
10
+ accessKeyId?: string;
11
+ secretAccessKey?: string;
12
+ securityToken?: string;
13
+ language: "en-us" | "zh-cn";
14
+ requestTimeoutMs: number;
15
+ defaultLookbackMinutes: number;
16
+ maxRecords: number;
17
+ fetchImpl?: typeof fetch;
18
+ };
19
+ export declare class TaurusApiSlowSqlSource implements SlowSqlSource {
20
+ private readonly endpoint;
21
+ private readonly projectId;
22
+ private readonly instanceId;
23
+ private readonly nodeId;
24
+ private readonly authToken?;
25
+ private readonly accessKeyId?;
26
+ private readonly secretAccessKey?;
27
+ private readonly securityToken?;
28
+ private readonly language;
29
+ private readonly requestTimeoutMs;
30
+ private readonly defaultLookbackMinutes;
31
+ private readonly maxRecords;
32
+ private readonly fetchImpl;
33
+ constructor(options: TaurusApiSlowSqlSourceOptions);
34
+ resolve(input: ResolveSlowSqlInput, ctx: SessionContext): Promise<ExternalSlowSqlSample | undefined>;
35
+ findTop(input: FindTopSlowSqlInput, ctx: SessionContext): Promise<ExternalSlowSqlSample[]>;
36
+ private fetchStatistics;
37
+ private fetchDetails;
38
+ private pickBestMatch;
39
+ private toExternalSample;
40
+ private postJson;
41
+ }
42
+ export {};
@@ -0,0 +1,149 @@
1
+ import { fetchHuaweiCloud } from "../../cloud/auth.js";
2
+ import { candidateToExternalSample, normalizeTimeRange, parseResponse, scoreCandidate, sortExternalSamples } from "./utils.js";
3
+ import { parseDetailCandidate, parseStatisticsCandidate, pickArrayCandidate } from "./parsers.js";
4
+ export class TaurusApiSlowSqlSource {
5
+ endpoint;
6
+ projectId;
7
+ instanceId;
8
+ nodeId;
9
+ authToken;
10
+ accessKeyId;
11
+ secretAccessKey;
12
+ securityToken;
13
+ language;
14
+ requestTimeoutMs;
15
+ defaultLookbackMinutes;
16
+ maxRecords;
17
+ fetchImpl;
18
+ constructor(options) {
19
+ this.endpoint = options.endpoint.replace(/\/+$/g, "");
20
+ this.projectId = options.projectId;
21
+ this.instanceId = options.instanceId;
22
+ this.nodeId = options.nodeId;
23
+ this.authToken = options.authToken;
24
+ this.accessKeyId = options.accessKeyId;
25
+ this.secretAccessKey = options.secretAccessKey;
26
+ this.securityToken = options.securityToken;
27
+ this.language = options.language;
28
+ this.requestTimeoutMs = options.requestTimeoutMs;
29
+ this.defaultLookbackMinutes = options.defaultLookbackMinutes;
30
+ this.maxRecords = options.maxRecords;
31
+ this.fetchImpl = options.fetchImpl ?? fetch;
32
+ }
33
+ async resolve(input, ctx) {
34
+ const timeWindow = normalizeTimeRange(input.timeRange, this.defaultLookbackMinutes);
35
+ const statisticCandidates = await this.fetchStatistics(timeWindow, ctx.database);
36
+ const matchedStatistic = this.pickBestMatch(statisticCandidates, input);
37
+ if (matchedStatistic) {
38
+ return this.toExternalSample(matchedStatistic, input);
39
+ }
40
+ const detailCandidates = await this.fetchDetails(timeWindow, ctx.database);
41
+ const matchedDetail = this.pickBestMatch(detailCandidates, input);
42
+ if (matchedDetail) {
43
+ return this.toExternalSample(matchedDetail, input);
44
+ }
45
+ return undefined;
46
+ }
47
+ async findTop(input, ctx) {
48
+ const timeWindow = normalizeTimeRange(input.timeRange, this.defaultLookbackMinutes);
49
+ const statisticCandidates = await this.fetchStatistics(timeWindow, ctx.database);
50
+ const samples = statisticCandidates
51
+ .map((candidate) => candidateToExternalSample(candidate, "taurus_api_slow_logs"))
52
+ .filter((value) => value !== undefined);
53
+ return sortExternalSamples(samples, input.sortBy).slice(0, Math.min(input.topN ?? 5, this.maxRecords));
54
+ }
55
+ async fetchStatistics(timeWindow, database) {
56
+ const path = `/v3/${this.projectId}/instances/${this.instanceId}/slow-logs/statistics`;
57
+ const payload = {
58
+ node_id: this.nodeId,
59
+ start_time: timeWindow.startTime,
60
+ end_time: timeWindow.endTime,
61
+ limit: this.maxRecords,
62
+ sort: "execute_time",
63
+ order: "desc",
64
+ };
65
+ if (database) {
66
+ payload.database = database;
67
+ }
68
+ const body = await this.postJson(path, payload);
69
+ return pickArrayCandidate(body)
70
+ .map((item) => parseStatisticsCandidate(item, `taurus_api:${path}`))
71
+ .filter((value) => value !== undefined);
72
+ }
73
+ async fetchDetails(timeWindow, database) {
74
+ const path = `/v3.1/${this.projectId}/instances/${this.instanceId}/slow-logs`;
75
+ const payload = {
76
+ node_id: this.nodeId,
77
+ start_time: timeWindow.startTime,
78
+ end_time: timeWindow.endTime,
79
+ offset: 0,
80
+ limit: this.maxRecords,
81
+ };
82
+ if (database) {
83
+ payload.database = database;
84
+ }
85
+ const body = await this.postJson(path, payload);
86
+ return pickArrayCandidate(body)
87
+ .map((item) => parseDetailCandidate(item, `taurus_api:${path}`))
88
+ .filter((value) => value !== undefined);
89
+ }
90
+ pickBestMatch(candidates, input) {
91
+ const scored = candidates
92
+ .map((candidate) => ({ candidate, score: scoreCandidate(candidate, input) }))
93
+ .sort((left, right) => right.score - left.score);
94
+ if (scored.length === 0) {
95
+ return undefined;
96
+ }
97
+ if (input.sqlHash || input.digestText) {
98
+ return scored[0].score > 0 ? scored[0].candidate : undefined;
99
+ }
100
+ return scored[0].candidate;
101
+ }
102
+ toExternalSample(candidate, input) {
103
+ const sample = candidateToExternalSample(candidate, "taurus_api_slow_logs");
104
+ if (!sample) {
105
+ return undefined;
106
+ }
107
+ return {
108
+ ...sample,
109
+ sqlHash: input.sqlHash ?? sample.sqlHash,
110
+ digestText: input.digestText ?? sample.digestText,
111
+ };
112
+ }
113
+ async postJson(path, payload) {
114
+ const controller = new AbortController();
115
+ const timer = setTimeout(() => controller.abort(), this.requestTimeoutMs);
116
+ try {
117
+ const body = JSON.stringify(payload);
118
+ const response = await fetchHuaweiCloud({
119
+ url: `${this.endpoint}${path}`,
120
+ method: "POST",
121
+ headers: {
122
+ "content-type": "application/json",
123
+ "x-language": this.language,
124
+ },
125
+ body,
126
+ auth: {
127
+ authToken: this.authToken,
128
+ accessKeyId: this.accessKeyId,
129
+ secretAccessKey: this.secretAccessKey,
130
+ securityToken: this.securityToken,
131
+ },
132
+ fetchImpl: (input, init) => this.fetchImpl(input, {
133
+ ...init,
134
+ signal: controller.signal,
135
+ }),
136
+ });
137
+ if (!response.ok) {
138
+ return {};
139
+ }
140
+ return parseResponse(response);
141
+ }
142
+ catch {
143
+ return {};
144
+ }
145
+ finally {
146
+ clearTimeout(timer);
147
+ }
148
+ }
149
+ }
@@ -0,0 +1,40 @@
1
+ import type { FindTopSlowSqlInput, DiagnosisWindow } from "../types.js";
2
+ import type { SessionContext } from "../../context/session-context.js";
3
+ export interface ResolveSlowSqlInput {
4
+ sqlHash?: string;
5
+ digestText?: string;
6
+ timeRange?: DiagnosisWindow;
7
+ }
8
+ export interface ExternalSlowSqlSample {
9
+ source: string;
10
+ sql: string;
11
+ sqlHash: string;
12
+ digestText?: string;
13
+ database?: string;
14
+ user?: string;
15
+ clientIp?: string;
16
+ startTime?: string;
17
+ execCount?: number;
18
+ avgLatencyMs?: number;
19
+ avgLockTimeMs?: number;
20
+ avgRowsExamined?: number;
21
+ rowsSent?: number;
22
+ rawRef?: string;
23
+ }
24
+ export interface SlowSqlSource {
25
+ resolve(input: ResolveSlowSqlInput, ctx: SessionContext): Promise<ExternalSlowSqlSample | undefined>;
26
+ findTop?(input: FindTopSlowSqlInput, ctx: SessionContext): Promise<ExternalSlowSqlSample[]>;
27
+ }
28
+ export type TaurusApiCandidate = {
29
+ sql?: string;
30
+ database?: string;
31
+ user?: string;
32
+ clientIp?: string;
33
+ startTime?: string;
34
+ execCount?: number;
35
+ avgLatencyMs?: number;
36
+ avgLockTimeMs?: number;
37
+ avgRowsExamined?: number;
38
+ rowsSent?: number;
39
+ rawRef?: string;
40
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ import type { DiagnosisWindow, FindTopSlowSqlInput } from "../types.js";
2
+ import type { ExternalSlowSqlSample, ResolveSlowSqlInput, TaurusApiCandidate } from "./types.js";
3
+ export declare function readString(value: unknown): string | undefined;
4
+ export declare function readNumber(value: unknown): number | undefined;
5
+ export declare function normalizeTimeRange(input: DiagnosisWindow | undefined, defaultLookbackMinutes: number): {
6
+ startTime: string;
7
+ endTime: string;
8
+ };
9
+ export declare function parseRelativeLookback(value: string | undefined): number | undefined;
10
+ export declare function formatTaurusApiTime(date: Date): string;
11
+ export declare function formatUnixSeconds(date: Date): string;
12
+ export declare function formatDigestTemplate(sql: string): string;
13
+ export declare function parseDurationMs(value: unknown): number | undefined;
14
+ export declare function secondsToMs(value: unknown): number | undefined;
15
+ export declare function scoreCandidate(candidate: TaurusApiCandidate, input: ResolveSlowSqlInput): number;
16
+ export declare function candidateToExternalSample(candidate: TaurusApiCandidate, source: string): ExternalSlowSqlSample | undefined;
17
+ export declare function sortExternalSamples(samples: ExternalSlowSqlSample[], sortBy: FindTopSlowSqlInput["sortBy"]): ExternalSlowSqlSample[];
18
+ export declare function parseResponse(response: Response): Promise<Record<string, unknown>>;
19
+ export declare function buildQueryString(params: Record<string, string | number | undefined>): string;
20
+ export declare function pickNextMarker(payload: Record<string, unknown>): string | undefined;
@@ -0,0 +1,170 @@
1
+ import { normalizeSql, sqlHash } from "../../utils/hash.js";
2
+ export function readString(value) {
3
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
4
+ }
5
+ export function readNumber(value) {
6
+ return typeof value === "number"
7
+ ? value
8
+ : typeof value === "string" && value.trim().length > 0
9
+ ? Number.parseFloat(value)
10
+ : undefined;
11
+ }
12
+ export function normalizeTimeRange(input, defaultLookbackMinutes) {
13
+ const now = new Date();
14
+ const end = input?.to ? new Date(input.to) : now;
15
+ const parsedRelative = parseRelativeLookback(input?.relative);
16
+ const start = input?.from
17
+ ? new Date(input.from)
18
+ : parsedRelative
19
+ ? new Date(end.getTime() - parsedRelative)
20
+ : new Date(end.getTime() - defaultLookbackMinutes * 60_000);
21
+ return {
22
+ startTime: formatTaurusApiTime(start),
23
+ endTime: formatTaurusApiTime(end),
24
+ };
25
+ }
26
+ export function parseRelativeLookback(value) {
27
+ if (!value) {
28
+ return undefined;
29
+ }
30
+ const match = value.trim().match(/^(\d+)\s*([mhd])$/i);
31
+ if (!match) {
32
+ return undefined;
33
+ }
34
+ const amount = Number.parseInt(match[1], 10);
35
+ const unit = match[2].toLowerCase();
36
+ switch (unit) {
37
+ case "m":
38
+ return amount * 60_000;
39
+ case "h":
40
+ return amount * 3_600_000;
41
+ case "d":
42
+ return amount * 86_400_000;
43
+ default:
44
+ return undefined;
45
+ }
46
+ }
47
+ export function formatTaurusApiTime(date) {
48
+ const iso = date.toISOString();
49
+ return `${iso.slice(0, 19)}Z`;
50
+ }
51
+ export function formatUnixSeconds(date) {
52
+ return String(Math.floor(date.getTime() / 1000));
53
+ }
54
+ export function formatDigestTemplate(sql) {
55
+ const withoutStrings = sql.replace(/'(?:''|[^'])*'|"(?:[""]|[^"])*"/g, "?");
56
+ const withoutNumbers = withoutStrings.replace(/\b\d+(?:\.\d+)?\b/g, "?");
57
+ return normalizeSql(withoutNumbers);
58
+ }
59
+ export function parseDurationMs(value) {
60
+ if (typeof value === "number") {
61
+ return value;
62
+ }
63
+ if (typeof value !== "string") {
64
+ return undefined;
65
+ }
66
+ const match = value.trim().match(/^([\d.]+)\s*(ms|s|us|µs)?$/i);
67
+ if (!match) {
68
+ return undefined;
69
+ }
70
+ const amount = Number.parseFloat(match[1]);
71
+ const unit = (match[2] ?? "ms").toLowerCase();
72
+ switch (unit) {
73
+ case "s":
74
+ return amount * 1000;
75
+ case "us":
76
+ case "µs":
77
+ return amount / 1000;
78
+ default:
79
+ return amount;
80
+ }
81
+ }
82
+ export function secondsToMs(value) {
83
+ const parsed = readNumber(value);
84
+ return parsed === undefined ? undefined : parsed * 1000;
85
+ }
86
+ export function scoreCandidate(candidate, input) {
87
+ if (!candidate.sql) {
88
+ return -1;
89
+ }
90
+ const candidateHash = sqlHash(normalizeSql(candidate.sql));
91
+ const candidateDigest = formatDigestTemplate(candidate.sql);
92
+ let score = 0;
93
+ if (input.sqlHash && input.sqlHash === candidateHash) {
94
+ score += 100;
95
+ }
96
+ if (input.digestText && formatDigestTemplate(input.digestText) === candidateDigest) {
97
+ score += 90;
98
+ }
99
+ if (candidate.avgLatencyMs !== undefined) {
100
+ score += Math.min(candidate.avgLatencyMs / 100, 20);
101
+ }
102
+ return score;
103
+ }
104
+ export function candidateToExternalSample(candidate, source) {
105
+ if (!candidate.sql) {
106
+ return undefined;
107
+ }
108
+ return {
109
+ source,
110
+ sql: candidate.sql,
111
+ sqlHash: sqlHash(normalizeSql(candidate.sql)),
112
+ digestText: formatDigestTemplate(candidate.sql),
113
+ database: candidate.database,
114
+ user: candidate.user,
115
+ clientIp: candidate.clientIp,
116
+ startTime: candidate.startTime,
117
+ execCount: candidate.execCount,
118
+ avgLatencyMs: candidate.avgLatencyMs,
119
+ avgLockTimeMs: candidate.avgLockTimeMs,
120
+ avgRowsExamined: candidate.avgRowsExamined,
121
+ rowsSent: candidate.rowsSent,
122
+ rawRef: candidate.rawRef,
123
+ };
124
+ }
125
+ export function sortExternalSamples(samples, sortBy) {
126
+ return [...samples].sort((left, right) => {
127
+ const leftExecCount = left.execCount ?? 0;
128
+ const rightExecCount = right.execCount ?? 0;
129
+ const leftAvgLatency = left.avgLatencyMs ?? 0;
130
+ const rightAvgLatency = right.avgLatencyMs ?? 0;
131
+ const leftTotalLatency = leftAvgLatency * Math.max(leftExecCount, 1);
132
+ const rightTotalLatency = rightAvgLatency * Math.max(rightExecCount, 1);
133
+ const leftLockTime = left.avgLockTimeMs ?? 0;
134
+ const rightLockTime = right.avgLockTimeMs ?? 0;
135
+ switch (sortBy) {
136
+ case "avg_latency":
137
+ return (rightAvgLatency - leftAvgLatency ||
138
+ rightTotalLatency - leftTotalLatency ||
139
+ rightExecCount - leftExecCount);
140
+ case "exec_count":
141
+ return (rightExecCount - leftExecCount ||
142
+ rightTotalLatency - leftTotalLatency ||
143
+ rightAvgLatency - leftAvgLatency);
144
+ case "lock_time":
145
+ return (rightLockTime - leftLockTime ||
146
+ rightTotalLatency - leftTotalLatency ||
147
+ rightExecCount - leftExecCount);
148
+ default:
149
+ return (rightTotalLatency - leftTotalLatency ||
150
+ rightAvgLatency - leftAvgLatency ||
151
+ rightExecCount - leftExecCount);
152
+ }
153
+ });
154
+ }
155
+ export async function parseResponse(response) {
156
+ const payload = (await response.json());
157
+ return payload && typeof payload === "object" && !Array.isArray(payload)
158
+ ? payload
159
+ : {};
160
+ }
161
+ export function buildQueryString(params) {
162
+ const entries = Object.entries(params).filter((entry) => entry[1] !== undefined);
163
+ return new URLSearchParams(entries.map(([key, value]) => [key, String(value)])).toString();
164
+ }
165
+ export function pickNextMarker(payload) {
166
+ return readString(payload.next_marker ??
167
+ payload.nextMarker ??
168
+ payload.marker ??
169
+ payload.offset);
170
+ }
@@ -0,0 +1,4 @@
1
+ export type { ResolveSlowSqlInput, ExternalSlowSqlSample, SlowSqlSource } from "./slow-sql-source/types.js";
2
+ export { TaurusApiSlowSqlSource } from "./slow-sql-source/taurus-api-source.js";
3
+ export { DasSlowSqlSource } from "./slow-sql-source/das-source.js";
4
+ export { buildResolveSlowSqlInput, createSlowSqlSource } from "./slow-sql-source/factory.js";
@@ -0,0 +1,3 @@
1
+ export { TaurusApiSlowSqlSource } from "./slow-sql-source/taurus-api-source.js";
2
+ export { DasSlowSqlSource } from "./slow-sql-source/das-source.js";
3
+ export { buildResolveSlowSqlInput, createSlowSqlSource } from "./slow-sql-source/factory.js";