taurusdb-core 0.3.0 → 0.5.0-rc.1

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 (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -1
  3. package/dist/audit/jsonl-writer.d.ts +47 -0
  4. package/dist/audit/jsonl-writer.js +124 -0
  5. package/dist/auth/sql-profile-loader/env-source.js +10 -0
  6. package/dist/auth/sql-profile-loader/parsing.js +11 -2
  7. package/dist/auth/sql-profile-loader/runtime-override.js +10 -2
  8. package/dist/auth/sql-profile-loader/types.d.ts +5 -0
  9. package/dist/capability/probe.js +3 -1
  10. package/dist/cloud/auth.d.ts +8 -0
  11. package/dist/cloud/auth.js +61 -3
  12. package/dist/cloud/csms.d.ts +7 -0
  13. package/dist/cloud/csms.js +60 -0
  14. package/dist/cloud/keychain.d.ts +28 -0
  15. package/dist/cloud/keychain.js +200 -0
  16. package/dist/cloud/kms.d.ts +7 -0
  17. package/dist/cloud/kms.js +86 -0
  18. package/dist/config/env.js +20 -0
  19. package/dist/config/schema.d.ts +88 -0
  20. package/dist/config/schema.js +21 -0
  21. package/dist/context/datasource-resolver.js +7 -0
  22. package/dist/context/session-context.d.ts +7 -0
  23. package/dist/diagnostics/metrics-source.d.ts +3 -0
  24. package/dist/diagnostics/metrics-source.js +7 -2
  25. package/dist/diagnostics/replication-lag.d.ts +4 -0
  26. package/dist/diagnostics/replication-lag.js +138 -0
  27. package/dist/diagnostics/slow-sql-source/das-source.d.ts +3 -0
  28. package/dist/diagnostics/slow-sql-source/das-source.js +3 -0
  29. package/dist/diagnostics/slow-sql-source/factory.js +9 -2
  30. package/dist/diagnostics/slow-sql-source/taurus-api-source.d.ts +3 -0
  31. package/dist/diagnostics/slow-sql-source/taurus-api-source.js +3 -0
  32. package/dist/diagnostics/types.d.ts +5 -1
  33. package/dist/diagnostics/types.js +7 -7
  34. package/dist/engine/runtime.d.ts +2 -2
  35. package/dist/engine/runtime.js +8 -14
  36. package/dist/engine/types.d.ts +3 -2
  37. package/dist/engine.d.ts +4 -3
  38. package/dist/engine.js +44 -2
  39. package/dist/executor/bounded-sql.d.ts +1 -0
  40. package/dist/executor/bounded-sql.js +10 -0
  41. package/dist/executor/concurrency-limiter.d.ts +15 -0
  42. package/dist/executor/concurrency-limiter.js +67 -0
  43. package/dist/executor/connection-pool.d.ts +3 -2
  44. package/dist/executor/connection-pool.js +36 -24
  45. package/dist/executor/sql-executor.d.ts +3 -0
  46. package/dist/executor/sql-executor.js +52 -9
  47. package/dist/executor/types.d.ts +5 -1
  48. package/dist/index.d.ts +13 -4
  49. package/dist/index.js +7 -1
  50. package/dist/safety/confirmation-store.d.ts +30 -7
  51. package/dist/safety/confirmation-store.js +154 -30
  52. package/dist/safety/guardrail.d.ts +3 -0
  53. package/dist/safety/guardrail.js +16 -6
  54. package/dist/safety/redaction.d.ts +6 -0
  55. package/dist/safety/redaction.js +47 -6
  56. package/dist/safety/sql-classifier.d.ts +1 -0
  57. package/dist/safety/sql-classifier.js +1 -0
  58. package/dist/safety/sql-validator.d.ts +1 -0
  59. package/dist/safety/sql-validator.js +24 -0
  60. package/dist/schema/adapters/mysql.js +3 -1
  61. package/dist/taurus/flashback.js +4 -10
  62. package/dist/taurus/recycle-bin.js +2 -8
  63. package/dist/utils/formatter.d.ts +6 -2
  64. package/dist/utils/formatter.js +7 -3
  65. package/dist/utils/logger.js +8 -0
  66. package/dist/utils/mysql-identifier.d.ts +1 -0
  67. package/dist/utils/mysql-identifier.js +9 -0
  68. package/package.json +14 -3
@@ -0,0 +1,67 @@
1
+ export class QueryConcurrencyError extends Error {
2
+ code = "SERVER_BUSY";
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "QueryConcurrencyError";
6
+ }
7
+ }
8
+ export class QueryConcurrencyLimiter {
9
+ maxConcurrent;
10
+ maxQueued;
11
+ queueTimeoutMs;
12
+ active = 0;
13
+ queue = [];
14
+ constructor(maxConcurrent, maxQueued, queueTimeoutMs) {
15
+ this.maxConcurrent = maxConcurrent;
16
+ this.maxQueued = maxQueued;
17
+ this.queueTimeoutMs = queueTimeoutMs;
18
+ }
19
+ async run(operation) {
20
+ const release = await this.acquire();
21
+ try {
22
+ return await operation();
23
+ }
24
+ finally {
25
+ release();
26
+ }
27
+ }
28
+ acquire() {
29
+ if (this.active < this.maxConcurrent) {
30
+ this.active += 1;
31
+ return Promise.resolve(this.releaseFactory());
32
+ }
33
+ if (this.queue.length >= this.maxQueued) {
34
+ return Promise.reject(new QueryConcurrencyError("Query concurrency queue is full."));
35
+ }
36
+ return new Promise((resolve, reject) => {
37
+ const waiter = {
38
+ resolve,
39
+ reject,
40
+ timer: setTimeout(() => {
41
+ const index = this.queue.indexOf(waiter);
42
+ if (index >= 0) {
43
+ this.queue.splice(index, 1);
44
+ }
45
+ reject(new QueryConcurrencyError("Timed out waiting for query capacity."));
46
+ }, this.queueTimeoutMs),
47
+ };
48
+ this.queue.push(waiter);
49
+ });
50
+ }
51
+ releaseFactory() {
52
+ let released = false;
53
+ return () => {
54
+ if (released) {
55
+ return;
56
+ }
57
+ released = true;
58
+ const waiter = this.queue.shift();
59
+ if (waiter) {
60
+ clearTimeout(waiter.timer);
61
+ waiter.resolve(this.releaseFactory());
62
+ return;
63
+ }
64
+ this.active -= 1;
65
+ };
66
+ }
67
+ }
@@ -18,6 +18,7 @@ export interface RawResult {
18
18
  export interface Session {
19
19
  id: string;
20
20
  datasource: string;
21
+ database?: string;
21
22
  mode: PoolMode;
22
23
  execute(sql: string, options?: ExecOptions): Promise<RawResult>;
23
24
  cancel(): Promise<void>;
@@ -35,7 +36,7 @@ export interface PoolHealth {
35
36
  }
36
37
  export interface ConnectionPool {
37
38
  acquire(datasource: string, mode: PoolMode, opts?: {
38
- allowReadonlyFallbackForMutations?: boolean;
39
+ database?: string;
39
40
  }): Promise<Session>;
40
41
  release(session: Session): Promise<void>;
41
42
  healthCheck(datasource: string): Promise<PoolHealth>;
@@ -91,7 +92,7 @@ export declare class ConnectionPoolManager implements ConnectionPool {
91
92
  private readonly activeSessions;
92
93
  constructor(options: ConnectionPoolManagerOptions);
93
94
  acquire(datasource: string, mode: PoolMode, opts?: {
94
- allowReadonlyFallbackForMutations?: boolean;
95
+ database?: string;
95
96
  }): Promise<Session>;
96
97
  release(session: Session): Promise<void>;
97
98
  healthCheck(datasource: string): Promise<PoolHealth>;
@@ -1,3 +1,4 @@
1
+ import { isIP } from "node:net";
1
2
  import { ulid } from "ulid";
2
3
  export class ConnectionPoolError extends Error {
3
4
  code = "CONNECTION_FAILED";
@@ -9,35 +10,42 @@ export class ConnectionPoolError extends Error {
9
10
  }
10
11
  }
11
12
  }
12
- function poolKey(datasource, mode) {
13
- return `${datasource}:${mode}`;
13
+ function poolKey(datasource, mode, database) {
14
+ return JSON.stringify([datasource, mode, database ?? null]);
14
15
  }
15
- async function resolveTls(tls, secretResolver) {
16
- if (!tls) {
16
+ async function resolveTls(tls, secretResolver, host, requireTls) {
17
+ if (!tls && !requireTls) {
17
18
  return undefined;
18
19
  }
20
+ if (requireTls && tls?.enabled === false) {
21
+ throw new ConnectionPoolError("TLS is required by server policy and cannot be disabled for this datasource.");
22
+ }
23
+ if (requireTls && tls?.rejectUnauthorized === false) {
24
+ throw new ConnectionPoolError("TLS certificate verification is required by server policy.");
25
+ }
19
26
  const resolved = {
20
- enabled: tls.enabled,
21
- rejectUnauthorized: tls.rejectUnauthorized,
22
- servername: tls.servername,
27
+ enabled: tls?.enabled ?? true,
28
+ rejectUnauthorized: tls?.rejectUnauthorized ?? true,
29
+ servername: tls?.servername ?? (isIP(host) === 0 ? host : undefined),
23
30
  };
24
- if (tls.ca) {
31
+ if (tls?.ca) {
25
32
  resolved.ca = await secretResolver.resolve(tls.ca);
26
33
  }
27
- if (tls.cert) {
34
+ if (tls?.cert) {
28
35
  resolved.cert = await secretResolver.resolve(tls.cert);
29
36
  }
30
- if (tls.key) {
37
+ if (tls?.key) {
31
38
  resolved.key = await secretResolver.resolve(tls.key);
32
39
  }
33
40
  return resolved;
34
41
  }
35
- function selectCredential(profile, mode, _opts = {}) {
36
- void mode;
37
- if (!profile.user) {
38
- throw new ConnectionPoolError(`Datasource "${profile.name}" does not define SQL credentials. Call begin_sql_login and complete the secure local login form before executing SQL.`);
42
+ function selectCredential(profile, mode) {
43
+ const credential = mode === "rw" ? profile.mutationUser : profile.user;
44
+ if (!credential) {
45
+ const credentialKind = mode === "rw" ? "mutation" : "read-only";
46
+ throw new ConnectionPoolError(`Datasource "${profile.name}" does not define ${credentialKind} SQL credentials. Configure a dedicated ${credentialKind} database username and password reference.`);
39
47
  }
40
- return profile.user;
48
+ return credential;
41
49
  }
42
50
  async function resolveCredentialValue(ref, secretResolver, context) {
43
51
  try {
@@ -65,7 +73,8 @@ export class ConnectionPoolManager {
65
73
  if (!profile) {
66
74
  throw new ConnectionPoolError(`Datasource profile not found: "${datasource}".`);
67
75
  }
68
- const entry = await this.getOrCreatePool(profile, mode, opts);
76
+ const database = opts.database ?? profile.database;
77
+ const entry = await this.getOrCreatePool(profile, mode, database);
69
78
  let driverSession;
70
79
  try {
71
80
  driverSession = await entry.pool.acquire();
@@ -79,6 +88,7 @@ export class ConnectionPoolManager {
79
88
  entryKey: entry.key,
80
89
  driverSession,
81
90
  datasource,
91
+ database,
82
92
  mode,
83
93
  };
84
94
  this.activeSessions.set(sessionId, active);
@@ -86,6 +96,7 @@ export class ConnectionPoolManager {
86
96
  return {
87
97
  id: sessionId,
88
98
  datasource,
99
+ database,
89
100
  mode,
90
101
  async execute(sql, options) {
91
102
  return active.driverSession.execute(sql, options);
@@ -151,13 +162,13 @@ export class ConnectionPoolManager {
151
162
  };
152
163
  }
153
164
  }
154
- async getOrCreatePool(profile, mode, opts = {}) {
155
- const key = poolKey(profile.name, mode);
165
+ async getOrCreatePool(profile, mode, database) {
166
+ const key = poolKey(profile.name, mode, database);
156
167
  const existing = this.pools.get(key);
157
168
  if (existing) {
158
169
  return existing instanceof Promise ? existing : existing;
159
170
  }
160
- const pending = this.createPool(profile, mode, opts)
171
+ const pending = this.createPool(profile, mode, database)
161
172
  .then((entry) => {
162
173
  this.pools.set(key, entry);
163
174
  return entry;
@@ -169,7 +180,7 @@ export class ConnectionPoolManager {
169
180
  this.pools.set(key, pending);
170
181
  return pending;
171
182
  }
172
- async createPool(profile, mode, opts = {}) {
183
+ async createPool(profile, mode, database) {
173
184
  const adapter = this.adapters[profile.engine];
174
185
  if (!adapter) {
175
186
  throw new ConnectionPoolError(`No driver adapter registered for engine "${profile.engine}".`);
@@ -177,9 +188,9 @@ export class ConnectionPoolManager {
177
188
  if (!profile.host) {
178
189
  throw new ConnectionPoolError(`Datasource "${profile.name}" does not define a host. Select a cloud instance or configure host in the datasource profile.`);
179
190
  }
180
- const credential = selectCredential(profile, mode, opts);
191
+ const credential = selectCredential(profile, mode);
181
192
  const password = await resolveCredentialValue(credential.password, this.secretResolver, `${profile.name}.${mode}.password`);
182
- const tls = await resolveTls(profile.tls, this.secretResolver);
193
+ const tls = await resolveTls(profile.tls, this.secretResolver, profile.host, this.config.security.requireTls);
183
194
  let pool;
184
195
  try {
185
196
  pool = await adapter.createPool({
@@ -188,7 +199,7 @@ export class ConnectionPoolManager {
188
199
  engine: profile.engine,
189
200
  host: profile.host,
190
201
  port: profile.port,
191
- database: profile.database,
202
+ database,
192
203
  username: credential.username,
193
204
  password,
194
205
  poolSize: profile.poolSize,
@@ -199,8 +210,9 @@ export class ConnectionPoolManager {
199
210
  throw new ConnectionPoolError(`Failed to create ${mode === "ro" ? "readonly" : "mutation"} pool for datasource "${profile.name}".`, error);
200
211
  }
201
212
  return {
202
- key: poolKey(profile.name, mode),
213
+ key: poolKey(profile.name, mode, database),
203
214
  datasource: profile.name,
215
+ database,
204
216
  mode,
205
217
  pool,
206
218
  };
@@ -11,6 +11,9 @@ export type SqlExecutorOptions = {
11
11
  historyLimit?: number;
12
12
  queryTracker?: QueryTracker;
13
13
  resultRedactor?: ResultRedactor;
14
+ maxConcurrentQueries?: number;
15
+ maxQueuedQueries?: number;
16
+ queueTimeoutMs?: number;
14
17
  };
15
18
  export declare class SqlExecutorImpl implements SqlExecutor {
16
19
  private readonly connectionPool;
@@ -3,6 +3,22 @@ import { buildExplainRecommendations, normalizeExplainRows, summarizeExplainRows
3
3
  import { createQueryTracker, } from "./query-tracker.js";
4
4
  import { createResultRedactor, } from "../safety/redaction.js";
5
5
  import { asFiniteNumber, inferColumns, normalizeRows } from "./result-normalizer.js";
6
+ import { QueryConcurrencyLimiter } from "./concurrency-limiter.js";
7
+ import { buildServerBoundedReadonlySql } from "./bounded-sql.js";
8
+ function isTimeoutError(error) {
9
+ return /timeout|timed out/i.test(error instanceof Error ? error.message : String(error));
10
+ }
11
+ async function cancelTimedOutSession(session, error) {
12
+ if (!isTimeoutError(error)) {
13
+ return;
14
+ }
15
+ try {
16
+ await session.cancel();
17
+ }
18
+ catch {
19
+ // Keep the original timeout error.
20
+ }
21
+ }
6
22
  export class SqlExecutorImpl {
7
23
  connectionPool;
8
24
  now;
@@ -25,7 +41,9 @@ export class SqlExecutorImpl {
25
41
  async explain(sql, ctx) {
26
42
  const queryId = this.queryIdGenerator();
27
43
  const startedAt = this.now();
28
- const session = await this.connectionPool.acquire(ctx.datasource, "ro");
44
+ const session = await this.connectionPool.acquire(ctx.datasource, "ro", {
45
+ database: ctx.database,
46
+ });
29
47
  const active = this.beginQuery(queryId, session, ctx, "ro", startedAt);
30
48
  try {
31
49
  const result = await session.execute(`EXPLAIN ${sql}`, {
@@ -45,6 +63,7 @@ export class SqlExecutorImpl {
45
63
  };
46
64
  }
47
65
  catch (error) {
66
+ await cancelTimedOutSession(session, error);
48
67
  const durationMs = this.now() - startedAt;
49
68
  this.completeQuery(active.queryId, active.cancelRequested ? "cancelled" : "failed", durationMs, error);
50
69
  throw error;
@@ -59,11 +78,16 @@ export class SqlExecutorImpl {
59
78
  const maxRows = opts.maxRows ?? ctx.limits.maxRows;
60
79
  const maxColumns = opts.maxColumns ?? ctx.limits.maxColumns;
61
80
  const maxFieldChars = opts.maxFieldChars ?? ctx.limits.maxFieldChars ?? 2048;
81
+ const maxResultBytes = opts.maxResultBytes ?? ctx.limits.maxResultBytes ?? 1048576;
82
+ const maxBlobBytes = opts.maxBlobBytes ?? ctx.limits.maxBlobBytes ?? 65536;
62
83
  const timeoutMs = opts.timeoutMs ?? ctx.limits.timeoutMs;
63
- const session = await this.connectionPool.acquire(ctx.datasource, "ro");
84
+ const session = await this.connectionPool.acquire(ctx.datasource, "ro", {
85
+ database: ctx.database,
86
+ });
64
87
  const active = this.beginQuery(queryId, session, ctx, "ro", startedAt);
65
88
  try {
66
- const result = await session.execute(sql, { timeoutMs });
89
+ const executionSql = buildServerBoundedReadonlySql(sql, maxRows);
90
+ const result = await session.execute(executionSql, { timeoutMs });
67
91
  const sourceRows = Array.isArray(result.rows) ? result.rows : [];
68
92
  const columns = inferColumns(result, sourceRows);
69
93
  const normalizedRows = normalizeRows(sourceRows, columns);
@@ -76,6 +100,9 @@ export class SqlExecutorImpl {
76
100
  maxRows,
77
101
  maxColumns,
78
102
  maxFieldChars,
103
+ maxResultBytes,
104
+ maxBlobBytes,
105
+ maskAllColumns: opts.maskAllColumns,
79
106
  sensitiveColumns: opts.sensitiveColumns,
80
107
  sensitiveStrategy: opts.sensitiveStrategy,
81
108
  });
@@ -91,6 +118,8 @@ export class SqlExecutorImpl {
91
118
  rowTruncated: redacted.rowTruncated,
92
119
  columnTruncated: redacted.columnTruncated,
93
120
  fieldTruncated: redacted.fieldTruncated,
121
+ byteTruncated: redacted.byteTruncated,
122
+ returnedBytes: redacted.returnedBytes,
94
123
  redactedColumns: redacted.redactedColumns,
95
124
  droppedColumns: redacted.droppedColumns,
96
125
  truncatedColumns: redacted.truncatedColumns,
@@ -98,6 +127,7 @@ export class SqlExecutorImpl {
98
127
  };
99
128
  }
100
129
  catch (error) {
130
+ await cancelTimedOutSession(session, error);
101
131
  const durationMs = this.now() - startedAt;
102
132
  this.completeQuery(active.queryId, active.cancelRequested ? "cancelled" : "failed", durationMs, error);
103
133
  throw error;
@@ -114,7 +144,7 @@ export class SqlExecutorImpl {
114
144
  const startedAt = this.now();
115
145
  const timeoutMs = opts.timeoutMs ?? ctx.limits.timeoutMs;
116
146
  const session = await this.connectionPool.acquire(ctx.datasource, "rw", {
117
- allowReadonlyFallbackForMutations: opts.allowReadonlyFallbackForMutations,
147
+ database: ctx.database,
118
148
  });
119
149
  const active = this.beginQuery(queryId, session, ctx, "rw", startedAt);
120
150
  try {
@@ -133,11 +163,16 @@ export class SqlExecutorImpl {
133
163
  };
134
164
  }
135
165
  catch (error) {
136
- try {
137
- await session.execute("ROLLBACK", { timeoutMs });
166
+ if (isTimeoutError(error)) {
167
+ await cancelTimedOutSession(session, error);
138
168
  }
139
- catch {
140
- // Ignore rollback failure and keep original error.
169
+ else {
170
+ try {
171
+ await session.execute("ROLLBACK", { timeoutMs });
172
+ }
173
+ catch {
174
+ // Ignore rollback failure and keep original error.
175
+ }
141
176
  }
142
177
  const durationMs = this.now() - startedAt;
143
178
  this.completeQuery(active.queryId, active.cancelRequested ? "cancelled" : "failed", durationMs, error);
@@ -245,5 +280,13 @@ export class SqlExecutorImpl {
245
280
  }
246
281
  }
247
282
  export function createSqlExecutor(options) {
248
- return new SqlExecutorImpl(options);
283
+ const executor = new SqlExecutorImpl(options);
284
+ const limiter = new QueryConcurrencyLimiter(options.maxConcurrentQueries ?? 8, options.maxQueuedQueries ?? 32, options.queueTimeoutMs ?? 5000);
285
+ return {
286
+ explain: (sql, ctx) => limiter.run(() => executor.explain(sql, ctx)),
287
+ executeReadonly: (sql, ctx, opts) => limiter.run(() => executor.executeReadonly(sql, ctx, opts)),
288
+ executeMutation: (sql, ctx, opts) => limiter.run(() => executor.executeMutation(sql, ctx, opts)),
289
+ getQueryStatus: (queryId) => executor.getQueryStatus(queryId),
290
+ cancelQuery: (queryId) => executor.cancelQuery(queryId),
291
+ };
249
292
  }
@@ -9,13 +9,15 @@ export interface ReadonlyOptions {
9
9
  maxRows?: number;
10
10
  maxColumns?: number;
11
11
  maxFieldChars?: number;
12
+ maxResultBytes?: number;
13
+ maxBlobBytes?: number;
14
+ maskAllColumns?: boolean;
12
15
  timeoutMs?: number;
13
16
  sensitiveColumns?: Iterable<string>;
14
17
  sensitiveStrategy?: SensitiveStrategy;
15
18
  }
16
19
  export interface MutationOptions {
17
20
  timeoutMs?: number;
18
- allowReadonlyFallbackForMutations?: boolean;
19
21
  }
20
22
  export interface QueryResult {
21
23
  queryId: string;
@@ -27,6 +29,8 @@ export interface QueryResult {
27
29
  rowTruncated: boolean;
28
30
  columnTruncated: boolean;
29
31
  fieldTruncated: boolean;
32
+ byteTruncated: boolean;
33
+ returnedBytes: number;
30
34
  redactedColumns: string[];
31
35
  droppedColumns: string[];
32
36
  truncatedColumns: string[];
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { TaurusDBEngine } from "./engine.js";
2
2
  export type { EnhancedExplainResult, ConfirmationOutcome, DataSourceInfo, IssueConfirmationInput, TaurusDBEngineCreateOptions, TaurusDBEngineDeps, } from "./engine.js";
3
+ export { createJsonlAuditWriter, JsonlAuditWriter, type AuditDecision, type AuditEvent, type AuditWriter, type JsonlAuditWriterOptions, } from "./audit/jsonl-writer.js";
3
4
  export { createConfigFromEnv, getConfig, redactConfigForLog, resetConfigForTests, } from "./config/index.js";
4
5
  export type { Config } from "./config/index.js";
5
6
  export { createSqlProfileLoader, RuntimeOverrideProfileLoader, } from "./auth/sql-profile-loader.js";
@@ -7,13 +8,15 @@ export type { DataSourceProfile, DatabaseEngine, ProfileLoader, RuntimeDataSourc
7
8
  export { DatasourceResolutionError } from "./context/datasource-resolver.js";
8
9
  export type { DatasourceResolveInput, DatasourceResolver, RuntimeLimits, SessionContext, } from "./context/session-context.js";
9
10
  export { ConnectionPoolError } from "./executor/connection-pool.js";
11
+ export { QueryConcurrencyError } from "./executor/concurrency-limiter.js";
12
+ export { buildServerBoundedReadonlySql } from "./executor/bounded-sql.js";
10
13
  export type { CancelResult, ExplainResult, MutationOptions, MutationResult, QueryResult, QueryStatus, ReadonlyOptions, SqlExecutor, } from "./executor/sql-executor.js";
11
14
  export { createCapabilityProbe } from "./capability/probe.js";
12
15
  export type { CapabilityProbe } from "./capability/probe.js";
13
16
  export { UnsupportedFeatureError } from "./capability/types.js";
14
17
  export type { CapabilitySnapshot, FeatureMatrix, FeatureStatus, KernelInfo, TaurusFeatureName, } from "./capability/types.js";
15
- export { createConfirmationStore, InMemoryConfirmationStore, } from "./safety/confirmation-store.js";
16
- export type { ConfirmationStore, ConfirmationToken, ConfirmationValidationResult, IssueInput, } from "./safety/confirmation-store.js";
18
+ export { createConfirmationStore, InMemoryConfirmationStore, parseApprovalRequest, signApprovalRequest, } from "./safety/confirmation-store.js";
19
+ export type { ConfirmationStore, ConfirmationRequest, ConfirmationValidationResult, IssueInput, } from "./safety/confirmation-store.js";
17
20
  export { createGuardrail } from "./safety/guardrail.js";
18
21
  export type { Guardrail, GuardrailDecision, GuardrailRuntimeLimits, InspectInput, } from "./safety/guardrail.js";
19
22
  export type { ExplainRiskSummary, RiskLevel, ValidationResult } from "./safety/sql-validator.js";
@@ -27,7 +30,13 @@ export { logger, withTaskContext } from "./utils/logger.js";
27
30
  export { CloudTaurusInstanceClient, createCloudTaurusInstanceClient, } from "./cloud/instances.js";
28
31
  export type { CloudTaurusInstanceSummary, ListCloudTaurusInstancesInput, } from "./cloud/instances.js";
29
32
  export { canAuthenticateHuaweiCloudRequests, fetchHuaweiCloud, getHuaweiCloudAuthFromConfig, hasHuaweiCloudCredentialAuth, inferHuaweiCloudRegionFromEndpoint, resolveHuaweiCloudProjectId, } from "./cloud/auth.js";
30
- export type { HuaweiCloudAuthOptions } from "./cloud/auth.js";
33
+ export type { HuaweiCloudAuthOptions, HuaweiCloudCredentialProvider, HuaweiCloudCredentials, } from "./cloud/auth.js";
34
+ export { createLinuxSecretServiceCredentialProvider, createMacOsKeychainCredentialProvider, createSystemCredentialProvider, createWindowsCredentialManagerProvider, } from "./cloud/keychain.js";
35
+ export type { LinuxSecretServiceCredentialProviderOptions, MacOsKeychainCredentialProviderOptions, SystemCredentialProviderOptions, WindowsCredentialManagerProviderOptions, } from "./cloud/keychain.js";
36
+ export { createHuaweiKmsSecretResolver } from "./cloud/kms.js";
37
+ export type { HuaweiKmsSecretResolverOptions } from "./cloud/kms.js";
38
+ export { createHuaweiCsmsSecretResolver } from "./cloud/csms.js";
39
+ export type { HuaweiCsmsSecretResolverOptions } from "./cloud/csms.js";
31
40
  export { FlashbackNoViewError, formatTimestamp as formatFlashbackTimestamp, } from "./taurus/flashback.js";
32
41
  export type { FlashbackInput, FlashbackNoViewDetails, } from "./taurus/flashback.js";
33
42
  export { buildListRecycleBinSql, buildRestoreRecycleBinTableSql, RECYCLE_BIN_DATABASE, } from "./taurus/recycle-bin.js";
@@ -35,6 +44,6 @@ export type { RecycleBinListResult, RecycleBinRestoreResult, RestoreRecycleBinTa
35
44
  export { createPlaceholderDiagnosticResult } from "./diagnostics/types.js";
36
45
  export { buildResolveSlowSqlInput, createSlowSqlSource, TaurusApiSlowSqlSource, } from "./diagnostics/slow-sql-source.js";
37
46
  export { CesMetricsSource, createMetricsSource, } from "./diagnostics/metrics-source.js";
38
- export type { DbHotspotItem, DbHotspotResult, DiagnosticBaseInput, DiagnosticConfidence, DiagnosticEvidenceItem, DiagnosticEvidenceLevel, DiagnosticNextToolInput, DiagnoseDbHotspotInput, DiagnoseServiceLatencyInput, FindTopSlowSqlInput, FindTopSlowSqlResult, DiagnosticResult, DiagnosticRootCauseCandidate, DiagnosticSeverity, DiagnosticStatus, ServiceLatencyCandidate, ServiceLatencyResult, ServiceLatencySuspectedCategory, DiagnosticSuspiciousEntities, DiagnosticToolName, DiagnosisWindow, DiagnoseConnectionSpikeInput, DiagnoseLockContentionInput, DiagnoseSlowQueryInput, DiagnoseStoragePressureInput, PlaceholderDiagnosticOptions, TopSlowSqlItem, } from "./diagnostics/types.js";
47
+ export type { DbHotspotItem, DbHotspotResult, DiagnosticBaseInput, DiagnosticConfidence, DiagnosticEvidenceItem, DiagnosticEvidenceLevel, DiagnosticNextToolInput, DiagnoseDbHotspotInput, DiagnoseServiceLatencyInput, FindTopSlowSqlInput, FindTopSlowSqlResult, DiagnosticResult, DiagnosticRootCauseCandidate, DiagnosticSeverity, DiagnosticStatus, ServiceLatencyCandidate, ServiceLatencyResult, ServiceLatencySuspectedCategory, DiagnosticSuspiciousEntities, DiagnosticToolName, DiagnosisWindow, DiagnoseConnectionSpikeInput, DiagnoseLockContentionInput, DiagnoseReplicationLagInput, DiagnoseSlowQueryInput, DiagnoseStoragePressureInput, PlaceholderDiagnosticOptions, TopSlowSqlItem, } from "./diagnostics/types.js";
39
48
  export type { ExternalSlowSqlSample, ResolveSlowSqlInput, SlowSqlSource, } from "./diagnostics/slow-sql-source.js";
40
49
  export type { MetricAlias, MetricPoint, MetricSummary, MetricsSource, QueryMetricsInput, } from "./diagnostics/metrics-source.js";
package/dist/index.js CHANGED
@@ -1,11 +1,14 @@
1
1
  export { TaurusDBEngine } from "./engine.js";
2
+ export { createJsonlAuditWriter, JsonlAuditWriter, } from "./audit/jsonl-writer.js";
2
3
  export { createConfigFromEnv, getConfig, redactConfigForLog, resetConfigForTests, } from "./config/index.js";
3
4
  export { createSqlProfileLoader, RuntimeOverrideProfileLoader, } from "./auth/sql-profile-loader.js";
4
5
  export { DatasourceResolutionError } from "./context/datasource-resolver.js";
5
6
  export { ConnectionPoolError } from "./executor/connection-pool.js";
7
+ export { QueryConcurrencyError } from "./executor/concurrency-limiter.js";
8
+ export { buildServerBoundedReadonlySql } from "./executor/bounded-sql.js";
6
9
  export { createCapabilityProbe } from "./capability/probe.js";
7
10
  export { UnsupportedFeatureError } from "./capability/types.js";
8
- export { createConfirmationStore, InMemoryConfirmationStore, } from "./safety/confirmation-store.js";
11
+ export { createConfirmationStore, InMemoryConfirmationStore, parseApprovalRequest, signApprovalRequest, } from "./safety/confirmation-store.js";
9
12
  export { createGuardrail } from "./safety/guardrail.js";
10
13
  export { SchemaIntrospectionError } from "./schema/introspector.js";
11
14
  export { ErrorCode, formatBlocked, formatConfirmationRequired, formatError, formatSuccess, } from "./utils/formatter.js";
@@ -14,6 +17,9 @@ export { generateQueryId, generateTaskId } from "./utils/id.js";
14
17
  export { logger, withTaskContext } from "./utils/logger.js";
15
18
  export { CloudTaurusInstanceClient, createCloudTaurusInstanceClient, } from "./cloud/instances.js";
16
19
  export { canAuthenticateHuaweiCloudRequests, fetchHuaweiCloud, getHuaweiCloudAuthFromConfig, hasHuaweiCloudCredentialAuth, inferHuaweiCloudRegionFromEndpoint, resolveHuaweiCloudProjectId, } from "./cloud/auth.js";
20
+ export { createLinuxSecretServiceCredentialProvider, createMacOsKeychainCredentialProvider, createSystemCredentialProvider, createWindowsCredentialManagerProvider, } from "./cloud/keychain.js";
21
+ export { createHuaweiKmsSecretResolver } from "./cloud/kms.js";
22
+ export { createHuaweiCsmsSecretResolver } from "./cloud/csms.js";
17
23
  export { FlashbackNoViewError, formatTimestamp as formatFlashbackTimestamp, } from "./taurus/flashback.js";
18
24
  export { buildListRecycleBinSql, buildRestoreRecycleBinTableSql, RECYCLE_BIN_DATABASE, } from "./taurus/recycle-bin.js";
19
25
  export { createPlaceholderDiagnosticResult } from "./diagnostics/types.js";
@@ -1,5 +1,20 @@
1
1
  import type { SessionContext } from "../context/session-context.js";
2
2
  import type { RiskLevel, ValidationResult } from "./sql-validator.js";
3
+ export type ApprovalRequestPayload = {
4
+ version: 1;
5
+ requestId: string;
6
+ sqlHash: string;
7
+ datasource: string;
8
+ database?: string;
9
+ host?: string;
10
+ port?: number;
11
+ projectId?: string;
12
+ instanceId?: string;
13
+ nodeId?: string;
14
+ riskLevel: RiskLevel;
15
+ issuedAt: number;
16
+ expiresAt: number;
17
+ };
3
18
  export type IssueInput = {
4
19
  sqlHash: string;
5
20
  normalizedSql: string;
@@ -7,38 +22,46 @@ export type IssueInput = {
7
22
  riskLevel: RiskLevel;
8
23
  ttlSeconds?: number;
9
24
  };
10
- export type ConfirmationToken = {
11
- token: string;
25
+ export type ConfirmationRequest = {
26
+ request: string;
27
+ requestId: string;
12
28
  issuedAt: number;
13
29
  expiresAt: number;
14
30
  };
15
31
  export type ConfirmationValidationResult = ValidationResult & {
16
32
  valid: boolean;
33
+ actor?: string;
17
34
  reason?: string;
18
35
  };
19
36
  export interface ConfirmationStore {
20
- issue(input: IssueInput): Promise<ConfirmationToken>;
37
+ issue(input: IssueInput): Promise<ConfirmationRequest>;
21
38
  validate(token: string, currentSql: string, ctx: SessionContext): Promise<ConfirmationValidationResult>;
22
- revoke(token: string): Promise<void>;
39
+ revoke(requestId: string): Promise<void>;
23
40
  }
24
41
  export type ConfirmationStoreOptions = {
42
+ approvalSecret?: string | Buffer;
25
43
  ttlSeconds?: number;
26
44
  cleanupIntervalMs?: number;
45
+ maxEntries?: number;
27
46
  now?: () => number;
28
47
  randomBytesFn?: (size: number) => Buffer;
29
48
  };
49
+ export declare function parseApprovalRequest(request: string): ApprovalRequestPayload;
50
+ export declare function signApprovalRequest(request: string, actor: string, secret: string | Buffer): string;
30
51
  export declare class InMemoryConfirmationStore implements ConfirmationStore {
31
52
  private readonly entries;
32
53
  private readonly now;
33
54
  private readonly ttlSeconds;
55
+ private readonly maxEntries;
34
56
  private readonly randomBytesFn;
57
+ private readonly approvalSecret?;
35
58
  private cleanupTimer?;
36
59
  constructor(options?: ConfirmationStoreOptions);
37
- issue(input: IssueInput): Promise<ConfirmationToken>;
60
+ issue(input: IssueInput): Promise<ConfirmationRequest>;
38
61
  validate(token: string, currentSql: string, ctx: SessionContext): Promise<ConfirmationValidationResult>;
39
- revoke(token: string): Promise<void>;
62
+ revoke(requestId: string): Promise<void>;
40
63
  stop(): void;
41
64
  cleanupExpired(now?: number): void;
42
- private generateUniqueToken;
65
+ private generateUniqueRequestId;
43
66
  }
44
67
  export declare function createConfirmationStore(options?: ConfirmationStoreOptions): ConfirmationStore;