taurusdb-core 0.4.0 → 0.5.0-rc.10

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 (56) 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 +6 -10
  6. package/dist/auth/sql-profile-loader/parsing.js +8 -5
  7. package/dist/auth/sql-profile-loader/runtime-override.d.ts +1 -0
  8. package/dist/auth/sql-profile-loader/runtime-override.js +19 -1
  9. package/dist/auth/sql-profile-loader/types.d.ts +5 -0
  10. package/dist/capability/probe.js +3 -1
  11. package/dist/cloud/auth.d.ts +1 -0
  12. package/dist/cloud/auth.js +37 -0
  13. package/dist/config/env.js +16 -0
  14. package/dist/config/schema.d.ts +78 -0
  15. package/dist/config/schema.js +19 -0
  16. package/dist/context/datasource-resolver.js +7 -0
  17. package/dist/context/session-context.d.ts +7 -0
  18. package/dist/diagnostics/replication-lag.d.ts +4 -0
  19. package/dist/diagnostics/replication-lag.js +138 -0
  20. package/dist/diagnostics/types.d.ts +5 -1
  21. package/dist/diagnostics/types.js +7 -7
  22. package/dist/engine/runtime.d.ts +2 -2
  23. package/dist/engine/runtime.js +8 -14
  24. package/dist/engine/types.d.ts +3 -2
  25. package/dist/engine.d.ts +5 -5
  26. package/dist/engine.js +32 -5
  27. package/dist/executor/bounded-sql.d.ts +1 -0
  28. package/dist/executor/bounded-sql.js +10 -0
  29. package/dist/executor/concurrency-limiter.d.ts +15 -0
  30. package/dist/executor/concurrency-limiter.js +67 -0
  31. package/dist/executor/connection-pool.d.ts +3 -2
  32. package/dist/executor/connection-pool.js +35 -24
  33. package/dist/executor/sql-executor.d.ts +3 -0
  34. package/dist/executor/sql-executor.js +52 -9
  35. package/dist/executor/types.d.ts +5 -1
  36. package/dist/index.d.ts +8 -3
  37. package/dist/index.js +5 -1
  38. package/dist/safety/confirmation-store.d.ts +30 -7
  39. package/dist/safety/confirmation-store.js +154 -30
  40. package/dist/safety/guardrail.d.ts +3 -0
  41. package/dist/safety/guardrail.js +16 -6
  42. package/dist/safety/redaction.d.ts +6 -0
  43. package/dist/safety/redaction.js +47 -6
  44. package/dist/safety/sql-classifier.d.ts +1 -0
  45. package/dist/safety/sql-classifier.js +1 -0
  46. package/dist/safety/sql-validator.d.ts +1 -0
  47. package/dist/safety/sql-validator.js +25 -1
  48. package/dist/schema/adapters/mysql.js +3 -1
  49. package/dist/taurus/flashback.js +4 -10
  50. package/dist/taurus/recycle-bin.js +2 -8
  51. package/dist/utils/formatter.d.ts +11 -2
  52. package/dist/utils/formatter.js +12 -3
  53. package/dist/utils/logger.js +8 -0
  54. package/dist/utils/mysql-identifier.d.ts +1 -0
  55. package/dist/utils/mysql-identifier.js +9 -0
  56. package/package.json +13 -2
@@ -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,41 @@ 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
+ }
19
23
  const resolved = {
20
- enabled: tls.enabled,
21
- rejectUnauthorized: tls.rejectUnauthorized,
22
- servername: tls.servername,
24
+ enabled: tls?.enabled ?? true,
25
+ // Dynamic cloud targets are commonly bound by public IP while the server
26
+ // certificate is issued to a DNS name. When TLS is explicitly enabled,
27
+ // make CA/hostname verification a separate profile opt-in.
28
+ rejectUnauthorized: tls?.rejectUnauthorized ?? false,
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. Configure a database username and password reference before executing SQL.`);
42
+ function selectCredential(profile, _mode) {
43
+ const credential = profile.user;
44
+ if (!credential) {
45
+ throw new ConnectionPoolError(`Datasource "${profile.name}" has no active SQL credential session. Select a TaurusDB instance and open the returned local login URL, or call begin_sql_login.`);
39
46
  }
40
- return profile.user;
47
+ return credential;
41
48
  }
42
49
  async function resolveCredentialValue(ref, secretResolver, context) {
43
50
  try {
@@ -65,7 +72,8 @@ export class ConnectionPoolManager {
65
72
  if (!profile) {
66
73
  throw new ConnectionPoolError(`Datasource profile not found: "${datasource}".`);
67
74
  }
68
- const entry = await this.getOrCreatePool(profile, mode, opts);
75
+ const database = opts.database ?? profile.database;
76
+ const entry = await this.getOrCreatePool(profile, mode, database);
69
77
  let driverSession;
70
78
  try {
71
79
  driverSession = await entry.pool.acquire();
@@ -79,6 +87,7 @@ export class ConnectionPoolManager {
79
87
  entryKey: entry.key,
80
88
  driverSession,
81
89
  datasource,
90
+ database,
82
91
  mode,
83
92
  };
84
93
  this.activeSessions.set(sessionId, active);
@@ -86,6 +95,7 @@ export class ConnectionPoolManager {
86
95
  return {
87
96
  id: sessionId,
88
97
  datasource,
98
+ database,
89
99
  mode,
90
100
  async execute(sql, options) {
91
101
  return active.driverSession.execute(sql, options);
@@ -151,13 +161,13 @@ export class ConnectionPoolManager {
151
161
  };
152
162
  }
153
163
  }
154
- async getOrCreatePool(profile, mode, opts = {}) {
155
- const key = poolKey(profile.name, mode);
164
+ async getOrCreatePool(profile, mode, database) {
165
+ const key = poolKey(profile.name, mode, database);
156
166
  const existing = this.pools.get(key);
157
167
  if (existing) {
158
168
  return existing instanceof Promise ? existing : existing;
159
169
  }
160
- const pending = this.createPool(profile, mode, opts)
170
+ const pending = this.createPool(profile, mode, database)
161
171
  .then((entry) => {
162
172
  this.pools.set(key, entry);
163
173
  return entry;
@@ -169,7 +179,7 @@ export class ConnectionPoolManager {
169
179
  this.pools.set(key, pending);
170
180
  return pending;
171
181
  }
172
- async createPool(profile, mode, opts = {}) {
182
+ async createPool(profile, mode, database) {
173
183
  const adapter = this.adapters[profile.engine];
174
184
  if (!adapter) {
175
185
  throw new ConnectionPoolError(`No driver adapter registered for engine "${profile.engine}".`);
@@ -177,9 +187,9 @@ export class ConnectionPoolManager {
177
187
  if (!profile.host) {
178
188
  throw new ConnectionPoolError(`Datasource "${profile.name}" does not define a host. Select a cloud instance or configure host in the datasource profile.`);
179
189
  }
180
- const credential = selectCredential(profile, mode, opts);
190
+ const credential = selectCredential(profile, mode);
181
191
  const password = await resolveCredentialValue(credential.password, this.secretResolver, `${profile.name}.${mode}.password`);
182
- const tls = await resolveTls(profile.tls, this.secretResolver);
192
+ const tls = await resolveTls(profile.tls, this.secretResolver, profile.host, this.config.security.requireTls);
183
193
  let pool;
184
194
  try {
185
195
  pool = await adapter.createPool({
@@ -188,7 +198,7 @@ export class ConnectionPoolManager {
188
198
  engine: profile.engine,
189
199
  host: profile.host,
190
200
  port: profile.port,
191
- database: profile.database,
201
+ database,
192
202
  username: credential.username,
193
203
  password,
194
204
  poolSize: profile.poolSize,
@@ -199,8 +209,9 @@ export class ConnectionPoolManager {
199
209
  throw new ConnectionPoolError(`Failed to create ${mode === "ro" ? "readonly" : "mutation"} pool for datasource "${profile.name}".`, error);
200
210
  }
201
211
  return {
202
- key: poolKey(profile.name, mode),
212
+ key: poolKey(profile.name, mode, database),
203
213
  datasource: profile.name,
214
+ database,
204
215
  mode,
205
216
  pool,
206
217
  };
@@ -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,14 +8,18 @@ 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";
21
+ export { createSqlParser } from "./safety/parser/index.js";
22
+ export type { SqlAst, StatementType as ParsedStatementType } from "./safety/parser/index.js";
18
23
  export type { Guardrail, GuardrailDecision, GuardrailRuntimeLimits, InspectInput, } from "./safety/guardrail.js";
19
24
  export type { ExplainRiskSummary, RiskLevel, ValidationResult } from "./safety/sql-validator.js";
20
25
  export { SchemaIntrospectionError } from "./schema/introspector.js";
@@ -41,6 +46,6 @@ export type { RecycleBinListResult, RecycleBinRestoreResult, RestoreRecycleBinTa
41
46
  export { createPlaceholderDiagnosticResult } from "./diagnostics/types.js";
42
47
  export { buildResolveSlowSqlInput, createSlowSqlSource, TaurusApiSlowSqlSource, } from "./diagnostics/slow-sql-source.js";
43
48
  export { CesMetricsSource, createMetricsSource, } from "./diagnostics/metrics-source.js";
44
- 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";
49
+ 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";
45
50
  export type { ExternalSlowSqlSample, ResolveSlowSqlInput, SlowSqlSource, } from "./diagnostics/slow-sql-source.js";
46
51
  export type { MetricAlias, MetricPoint, MetricSummary, MetricsSource, QueryMetricsInput, } from "./diagnostics/metrics-source.js";
package/dist/index.js CHANGED
@@ -1,12 +1,16 @@
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";
13
+ export { createSqlParser } from "./safety/parser/index.js";
10
14
  export { SchemaIntrospectionError } from "./schema/introspector.js";
11
15
  export { ErrorCode, formatBlocked, formatConfirmationRequired, formatError, formatSuccess, } from "./utils/formatter.js";
12
16
  export { normalizeSql, sqlHash } from "./utils/hash.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;