taurusdb-core 0.5.0-rc.10 → 0.5.0-rc.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.
@@ -12,8 +12,7 @@ export function parseEngineFromDsnProtocol(protocol) {
12
12
  export function parseEnvProfile(env) {
13
13
  const dsn = asString(env.TAURUSDB_SQL_DSN);
14
14
  const explicitHost = asString(env.TAURUSDB_SQL_HOST);
15
- const explicitProfileName = asString(env.TAURUSDB_SQL_DATASOURCE);
16
- const profileName = explicitProfileName ?? "taurus_mcp";
15
+ const profileName = asString(env.TAURUSDB_SQL_DATASOURCE) ?? "taurus_mcp";
17
16
  let engine;
18
17
  let host;
19
18
  let port;
@@ -41,7 +40,6 @@ export function parseEnvProfile(env) {
41
40
  }
42
41
  if (!dsn &&
43
42
  !explicitHost &&
44
- !explicitProfileName &&
45
43
  !asString(env.TAURUSDB_SQL_USER) &&
46
44
  !asString(env.TAURUSDB_SQL_PASSWORD) &&
47
45
  !database) {
@@ -51,13 +49,23 @@ export function parseEnvProfile(env) {
51
49
  throw new Error("Failed to resolve SQL port from environment.");
52
50
  }
53
51
  username = username ?? asString(env.TAURUSDB_SQL_USER);
52
+ if (!username) {
53
+ throw new Error("Missing SQL username in environment. Set TAURUSDB_SQL_USER or include it in DSN.");
54
+ }
54
55
  passwordRef =
55
56
  passwordRef ??
56
57
  (Object.hasOwn(env, "TAURUSDB_SQL_PASSWORD")
57
58
  ? parseCredentialRef(env.TAURUSDB_SQL_PASSWORD, "TAURUSDB_SQL_PASSWORD")
58
59
  : undefined);
59
- if ((username && !passwordRef) || (!username && passwordRef)) {
60
- throw new Error("SQL credentials require both username and password. Omit both to use the local database login page.");
60
+ if (!passwordRef) {
61
+ throw new Error("Missing SQL password in environment. Set TAURUSDB_SQL_PASSWORD or include it in DSN.");
62
+ }
63
+ const mutationUsername = asString(env.TAURUSDB_SQL_MUTATION_USER);
64
+ const mutationPasswordRef = Object.hasOwn(env, "TAURUSDB_SQL_MUTATION_PASSWORD")
65
+ ? parseCredentialRef(env.TAURUSDB_SQL_MUTATION_PASSWORD, "TAURUSDB_SQL_MUTATION_PASSWORD")
66
+ : undefined;
67
+ if ((mutationUsername && !mutationPasswordRef) || (!mutationUsername && mutationPasswordRef)) {
68
+ throw new Error("Mutation credentials require both TAURUSDB_SQL_MUTATION_USER and TAURUSDB_SQL_MUTATION_PASSWORD.");
61
69
  }
62
70
  const poolSize = asInteger(env.TAURUSDB_SQL_POOL_SIZE);
63
71
  if (poolSize !== undefined && poolSize <= 0) {
@@ -69,7 +77,13 @@ export function parseEnvProfile(env) {
69
77
  host,
70
78
  port,
71
79
  database,
72
- user: username && passwordRef ? { username, password: passwordRef } : undefined,
80
+ user: {
81
+ username,
82
+ password: passwordRef,
83
+ },
84
+ mutationUser: mutationUsername && mutationPasswordRef
85
+ ? { username: mutationUsername, password: mutationPasswordRef }
86
+ : undefined,
73
87
  poolSize,
74
88
  });
75
89
  }
@@ -196,14 +196,19 @@ export function parseProfileRecord(name, value, context) {
196
196
  if (poolSize !== undefined && poolSize <= 0) {
197
197
  throw new Error(`Invalid datasource profile ${name} in ${context}: poolSize must be positive.`);
198
198
  }
199
- // `user` is the session credential. Keep older read-only aliases for compatibility.
199
+ // `user` is the read-only credential. Keep older read-only aliases for compatibility.
200
200
  const userRaw = value.user ??
201
201
  value.readonlyUser ??
202
202
  value.readonly ??
203
203
  value.readOnlyUser;
204
- const user = userRaw === undefined
204
+ if (userRaw === undefined) {
205
+ throw new Error(`Invalid datasource profile ${name} in ${context}: missing user.`);
206
+ }
207
+ const user = parseUserCredential(userRaw, `${context}.${name}.user`);
208
+ const mutationUserRaw = value.mutationUser ?? value.writeUser ?? value.rwUser;
209
+ const mutationUser = mutationUserRaw === undefined
205
210
  ? undefined
206
- : parseUserCredential(userRaw, `${context}.${name}.user`);
211
+ : parseUserCredential(mutationUserRaw, `${context}.${name}.mutationUser`);
207
212
  const tls = parseTlsOptions(value.tls, `${context}.${name}.tls`);
208
213
  return withRedactedToString({
209
214
  name,
@@ -214,6 +219,7 @@ export function parseProfileRecord(name, value, context) {
214
219
  instanceId,
215
220
  nodeId,
216
221
  user,
222
+ mutationUser,
217
223
  tls,
218
224
  poolSize,
219
225
  });
@@ -33,8 +33,10 @@ export interface DataSourceProfile {
33
33
  database?: string;
34
34
  instanceId?: string;
35
35
  nodeId?: string;
36
- /** Session credential used by guarded query tools and the human-gated recovery path. */
36
+ /** Read-only credential used by discovery, diagnostics, and query tools. */
37
37
  user?: UserCredential;
38
+ /** Separate credential required for mutation tools. No fallback is allowed. */
39
+ mutationUser?: UserCredential;
38
40
  tls?: TlsOptions;
39
41
  poolSize?: number;
40
42
  toString(): string;
@@ -161,7 +161,6 @@ export function buildRawConfigFromEnv(env) {
161
161
  },
162
162
  security: {
163
163
  dynamicTargetsEnabled: parseBoolean(env.TAURUSDB_ENABLE_DYNAMIC_TARGETS, "TAURUSDB_ENABLE_DYNAMIC_TARGETS"),
164
- recycleBinRestoreEnabled: parseBoolean(env.TAURUSDB_ENABLE_RECYCLE_BIN_RESTORE, "TAURUSDB_ENABLE_RECYCLE_BIN_RESTORE"),
165
164
  requireTls: parseBoolean(env.TAURUSDB_REQUIRE_TLS, "TAURUSDB_REQUIRE_TLS"),
166
165
  approvalSecretPath: expandTildePath(readString(env.TAURUSDB_MUTATION_APPROVAL_SECRET_FILE)),
167
166
  approvalTtlSeconds: parseInteger(env.TAURUSDB_MUTATION_APPROVAL_TTL_SECONDS, "TAURUSDB_MUTATION_APPROVAL_TTL_SECONDS"),
@@ -106,7 +106,6 @@ export declare const ConfigSchema: z.ZodObject<{
106
106
  }>>;
107
107
  security: z.ZodDefault<z.ZodObject<{
108
108
  dynamicTargetsEnabled: z.ZodDefault<z.ZodBoolean>;
109
- recycleBinRestoreEnabled: z.ZodDefault<z.ZodBoolean>;
110
109
  requireTls: z.ZodDefault<z.ZodBoolean>;
111
110
  approvalSecretPath: z.ZodOptional<z.ZodString>;
112
111
  approvalTtlSeconds: z.ZodDefault<z.ZodNumber>;
@@ -114,7 +113,6 @@ export declare const ConfigSchema: z.ZodObject<{
114
113
  credentialMaxTtlMinutes: z.ZodDefault<z.ZodNumber>;
115
114
  }, "strip", z.ZodTypeAny, {
116
115
  dynamicTargetsEnabled: boolean;
117
- recycleBinRestoreEnabled: boolean;
118
116
  requireTls: boolean;
119
117
  approvalTtlSeconds: number;
120
118
  credentialIdleTtlMinutes: number;
@@ -122,7 +120,6 @@ export declare const ConfigSchema: z.ZodObject<{
122
120
  approvalSecretPath?: string | undefined;
123
121
  }, {
124
122
  dynamicTargetsEnabled?: boolean | undefined;
125
- recycleBinRestoreEnabled?: boolean | undefined;
126
123
  requireTls?: boolean | undefined;
127
124
  approvalSecretPath?: string | undefined;
128
125
  approvalTtlSeconds?: number | undefined;
@@ -365,7 +362,6 @@ export declare const ConfigSchema: z.ZodObject<{
365
362
  };
366
363
  security: {
367
364
  dynamicTargetsEnabled: boolean;
368
- recycleBinRestoreEnabled: boolean;
369
365
  requireTls: boolean;
370
366
  approvalTtlSeconds: number;
371
367
  credentialIdleTtlMinutes: number;
@@ -458,7 +454,6 @@ export declare const ConfigSchema: z.ZodObject<{
458
454
  } | undefined;
459
455
  security?: {
460
456
  dynamicTargetsEnabled?: boolean | undefined;
461
- recycleBinRestoreEnabled?: boolean | undefined;
462
457
  requireTls?: boolean | undefined;
463
458
  approvalSecretPath?: string | undefined;
464
459
  approvalTtlSeconds?: number | undefined;
@@ -22,9 +22,8 @@ const AuditSchema = z
22
22
  .default({});
23
23
  const SecuritySchema = z
24
24
  .object({
25
- dynamicTargetsEnabled: z.boolean().default(true),
26
- recycleBinRestoreEnabled: z.boolean().default(true),
27
- requireTls: z.boolean().default(false),
25
+ dynamicTargetsEnabled: z.boolean().default(false),
26
+ requireTls: z.boolean().default(true),
28
27
  approvalSecretPath: z.string().min(1).optional(),
29
28
  approvalTtlSeconds: z.number().int().positive().max(3600).default(300),
30
29
  credentialIdleTtlMinutes: z.number().int().positive().max(30).default(30),
package/dist/engine.d.ts CHANGED
@@ -5,12 +5,11 @@ import type { CapabilitySnapshot, FeatureMatrix, KernelInfo } from "./capability
5
5
  import { type Config } from "./config/index.js";
6
6
  import type { DatasourceResolveInput, DatasourceResolver, SessionContext } from "./context/session-context.js";
7
7
  import { type ConnectionPool } from "./executor/connection-pool.js";
8
- import { type CancelResult, type ExplainResult, type MutationOptions, type MutationResult, type QueryResult, type QueryStatus, type ReadonlyOptions, type SqlExecutor } from "./executor/sql-executor.js";
8
+ import { type CancelResult, type ExplainResult, type QueryResult, type QueryStatus, type ReadonlyOptions, type SqlExecutor } from "./executor/sql-executor.js";
9
9
  import { type ConfirmationStore, type ConfirmationRequest, type ConfirmationValidationResult } from "./safety/confirmation-store.js";
10
10
  import { type Guardrail, type GuardrailDecision, type InspectInput } from "./safety/guardrail.js";
11
11
  import { type DatabaseInfo, type SchemaIntrospector, type TableInfo, type TableSchema } from "./schema/introspector.js";
12
12
  import { type FlashbackInput } from "./taurus/flashback.js";
13
- import type { RestoreRecycleBinTableInput } from "./taurus/recycle-bin.js";
14
13
  import { type DbHotspotResult, type DiagnoseDbHotspotInput, type DiagnoseServiceLatencyInput, type FindTopSlowSqlInput, type FindTopSlowSqlResult, type DiagnoseConnectionSpikeInput, type DiagnoseLockContentionInput, type DiagnoseSlowQueryInput, type DiagnoseStoragePressureInput, type DiagnoseReplicationLagInput, type DiagnosticResult, type ServiceLatencyResult } from "./diagnostics/types.js";
15
14
  import { type SlowSqlSource } from "./diagnostics/slow-sql-source.js";
16
15
  import { type MetricsSource } from "./diagnostics/metrics-source.js";
@@ -67,7 +66,6 @@ export declare class TaurusDBEngine {
67
66
  executeReadonly(sql: string, ctx: SessionContext, opts?: ReadonlyOptions): Promise<QueryResult>;
68
67
  flashbackQuery(input: FlashbackInput, ctx: SessionContext, opts?: ReadonlyOptions): Promise<QueryResult>;
69
68
  listRecycleBin(ctx: SessionContext, opts?: ReadonlyOptions): Promise<QueryResult>;
70
- restoreRecycleBinTable(input: RestoreRecycleBinTableInput, ctx: SessionContext, opts?: MutationOptions): Promise<MutationResult>;
71
69
  getQueryStatus(queryId: string): Promise<QueryStatus>;
72
70
  cancelQuery(queryId: string): Promise<CancelResult>;
73
71
  issueConfirmation(input: IssueConfirmationInput): Promise<ConfirmationRequest>;
package/dist/engine.js CHANGED
@@ -18,7 +18,7 @@ import { createSlowSqlSource, } from "./diagnostics/slow-sql-source.js";
18
18
  import { createMetricsSource, } from "./diagnostics/metrics-source.js";
19
19
  import { findLatestDeadlock, findMetadataLockWaits, findStatementDigestCandidatesForSqlHints, findStatementDigestSample, findStatementDigestSampleForSql, findStatementWaitEvents, findStorageStatementDigests, findTableStorageStats, findTopStatementDigests, isPerformanceSchemaEnabled, showLockWaits, showProcesslist, } from "./engine/data-access.js";
20
20
  import { diagnoseConnectionSpike, diagnoseDbHotspot, diagnoseLockContention, diagnoseServiceLatency, diagnoseSlowQuery, diagnoseStoragePressure, findTopSlowSql, } from "./engine/diagnostics.js";
21
- import { cancelQuery, close, executeReadonly, explain, explainEnhanced, flashbackQuery, getQueryStatus, handleConfirmation, issueConfirmation, listRecycleBin, restoreRecycleBinTable, validateConfirmation, } from "./engine/runtime.js";
21
+ import { cancelQuery, close, executeReadonly, explain, explainEnhanced, flashbackQuery, getQueryStatus, handleConfirmation, issueConfirmation, listRecycleBin, validateConfirmation, } from "./engine/runtime.js";
22
22
  async function readMutationApprovalSecret(filePath) {
23
23
  const info = await lstat(filePath);
24
24
  if (!info.isFile() || info.isSymbolicLink()) {
@@ -251,9 +251,6 @@ export class TaurusDBEngine {
251
251
  async listRecycleBin(ctx, opts) {
252
252
  return listRecycleBin(this, ctx, opts);
253
253
  }
254
- async restoreRecycleBinTable(input, ctx, opts) {
255
- return restoreRecycleBinTable(this, input, ctx, opts);
256
- }
257
254
  async getQueryStatus(queryId) {
258
255
  return getQueryStatus(this, queryId);
259
256
  }
@@ -20,12 +20,12 @@ async function resolveTls(tls, secretResolver, host, requireTls) {
20
20
  if (requireTls && tls?.enabled === false) {
21
21
  throw new ConnectionPoolError("TLS is required by server policy and cannot be disabled for this datasource.");
22
22
  }
23
+ if (requireTls && tls?.rejectUnauthorized === false) {
24
+ throw new ConnectionPoolError("TLS certificate verification is required by server policy.");
25
+ }
23
26
  const resolved = {
24
27
  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,
28
+ rejectUnauthorized: tls?.rejectUnauthorized ?? true,
29
29
  servername: tls?.servername ?? (isIP(host) === 0 ? host : undefined),
30
30
  };
31
31
  if (tls?.ca) {
@@ -39,10 +39,11 @@ async function resolveTls(tls, secretResolver, host, requireTls) {
39
39
  }
40
40
  return resolved;
41
41
  }
42
- function selectCredential(profile, _mode) {
43
- const credential = profile.user;
42
+ function selectCredential(profile, mode) {
43
+ const credential = mode === "rw" ? profile.mutationUser : profile.user;
44
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.`);
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.`);
46
47
  }
47
48
  return credential;
48
49
  }
@@ -10,11 +10,6 @@ export declare const ErrorCode: {
10
10
  readonly QUERY_TIMEOUT: "QUERY_TIMEOUT";
11
11
  readonly QUERY_CANCELLED: "QUERY_CANCELLED";
12
12
  readonly CONNECTION_FAILED: "CONNECTION_FAILED";
13
- readonly DB_ENDPOINT_UNREACHABLE: "DB_ENDPOINT_UNREACHABLE";
14
- readonly DB_CONNECTION_REFUSED: "DB_CONNECTION_REFUSED";
15
- readonly DB_TLS_FAILED: "DB_TLS_FAILED";
16
- readonly DB_AUTH_FAILED: "DB_AUTH_FAILED";
17
- readonly DB_VALIDATION_TIMEOUT: "DB_VALIDATION_TIMEOUT";
18
13
  readonly RESULT_TOO_LARGE: "RESULT_TOO_LARGE";
19
14
  readonly AUDIT_FAILED: "AUDIT_FAILED";
20
15
  readonly SERVER_BUSY: "SERVER_BUSY";
@@ -9,11 +9,6 @@ export const ErrorCode = {
9
9
  QUERY_TIMEOUT: "QUERY_TIMEOUT",
10
10
  QUERY_CANCELLED: "QUERY_CANCELLED",
11
11
  CONNECTION_FAILED: "CONNECTION_FAILED",
12
- DB_ENDPOINT_UNREACHABLE: "DB_ENDPOINT_UNREACHABLE",
13
- DB_CONNECTION_REFUSED: "DB_CONNECTION_REFUSED",
14
- DB_TLS_FAILED: "DB_TLS_FAILED",
15
- DB_AUTH_FAILED: "DB_AUTH_FAILED",
16
- DB_VALIDATION_TIMEOUT: "DB_VALIDATION_TIMEOUT",
17
12
  RESULT_TOO_LARGE: "RESULT_TOO_LARGE",
18
13
  AUDIT_FAILED: "AUDIT_FAILED",
19
14
  SERVER_BUSY: "SERVER_BUSY",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taurusdb-core",
3
- "version": "0.5.0-rc.10",
3
+ "version": "0.5.0-rc.3",
4
4
  "description": "Shared TaurusDB data-plane engine for schema, SQL execution, guardrails, and diagnostics.",
5
5
  "license": "MIT",
6
6
  "repository": {