@fadhilp/stateql 0.5.4 → 0.6.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.
package/README.md CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  StateQL is a stateful database CLI and TypeScript library for AI agents and
4
4
  automation. It provides a safe interface for querying, changing, and inspecting
5
- SQLite, PostgreSQL, and MySQL databases while keeping results reusable and
6
- operations traceable across commands.
5
+ SQLite, PostgreSQL, MySQL, and MongoDB databases while keeping results reusable
6
+ and operations traceable across commands.
7
7
 
8
8
  StateQL is built around durable handles:
9
9
 
@@ -80,7 +80,7 @@ A connection accepts exactly one source: a direct target, `--env`, or
80
80
  `--profile`.
81
81
 
82
82
  ```bash
83
- stql connect <sqlite-path|postgres-url|mysql-url> [--name NAME] [--read-write]
83
+ stql connect <sqlite-path|postgres-url|mysql-url|mongodb-url> [--name NAME] [--read-write]
84
84
  stql connect --env ENV [--name NAME] [--read-write]
85
85
  stql connect --profile NAME
86
86
  stql disconnect
@@ -89,9 +89,9 @@ stql status
89
89
 
90
90
  ### Environment-backed credentials
91
91
 
92
- PostgreSQL and MySQL credentials should come from environment variables. The
93
- variable must contain the complete connection URL, not only its password.
94
- Environment-backed SQLite paths require an explicit `sqlite:` prefix.
92
+ PostgreSQL, MySQL, and MongoDB credentials should come from environment
93
+ variables. The variable must contain the complete connection URL, not only its
94
+ password. Environment-backed SQLite paths require an explicit `sqlite:` prefix.
95
95
 
96
96
  ```bash
97
97
  export APP_DATABASE_URL='postgres://user:password@host/app'
@@ -100,12 +100,16 @@ stql connect --env APP_DATABASE_URL --name app --read-only
100
100
  export MYSQL_DATABASE_URL='mysql://user:password@host/app'
101
101
  stql connect --env MYSQL_DATABASE_URL --name mysql-app --read-only
102
102
 
103
+ export MONGODB_URL='mongodb://user:password@host/app'
104
+ stql connect --env MONGODB_URL --name mongo-app --read-only
105
+
103
106
  export SQLITE_DATABASE='sqlite:./app.sqlite'
104
107
  stql connect --env SQLITE_DATABASE --name local --read-only
105
108
  ```
106
109
 
107
- StateQL stores no PostgreSQL or MySQL password. Credential-bearing URLs must be
108
- supplied through `--env`. SQLite paths remain persisted as connection metadata.
110
+ StateQL stores no PostgreSQL, MySQL, or MongoDB password. Credential-bearing
111
+ URLs must be supplied through `--env`. SQLite paths remain persisted as
112
+ connection metadata.
109
113
 
110
114
  ### Local profiles
111
115
 
@@ -135,11 +139,13 @@ otherwise it remains a path or database URL.
135
139
  `uselibpqcompat=true` opts out and keeps libpq-compatible SSL semantics.
136
140
  - **MySQL:** uses positional `?` parameters. MariaDB compatibility is not
137
141
  currently claimed.
142
+ - **MongoDB:** supports `mongodb://` and `mongodb+srv://` URLs with an explicit
143
+ database path. SQL methods are rejected; use the native MongoDB methods below.
138
144
 
139
145
  ## CLI reference
140
146
 
141
147
  ```text
142
- stql connect <sqlite-path|postgres-url|mysql-url> [--name NAME] [--read-write]
148
+ stql connect <sqlite-path|postgres-url|mysql-url|mongodb-url> [--name NAME] [--read-write]
143
149
  stql connect --env ENV [--name NAME] [--read-write]
144
150
  stql connect --profile NAME
145
151
  stql disconnect
@@ -150,11 +156,13 @@ stql query <sql> [--params JSON | --param VALUE...] [--cache auto|bypass|require
150
156
  stql filter <result-handle> <predicate> [--params JSON | --param VALUE...]
151
157
  stql exec <sql> [--params JSON | --param VALUE...] [--idempotency-key KEY] [--replay]
152
158
  [--allow-unbounded] [--allow-destructive]
159
+ stql mongo query|exec|plan '<EJSON command>' [--cache MODE] [--idempotency-key KEY]
160
+ [--replay] [--allow-unbounded] [--allow-destructive]
153
161
  stql show|count|columns <result-handle>
154
162
  stql rows <result-handle> [--offset N] [--limit N]
155
163
  stql alias set <name> <result-handle>
156
164
  stql export <result-handle> --output FILE [--format json|jsonl|csv]
157
- stql inspect schema|table|columns|indexes|constraints [table]
165
+ stql inspect schema|table|collection|collections|columns|indexes|constraints [name]
158
166
  stql transaction begin|status|commit|rollback [--isolation LEVEL]
159
167
  stql plan <sql> [--allow-unbounded] [--allow-destructive]
160
168
  stql apply <plan-handle>
@@ -181,6 +189,38 @@ Use `--params JSON` for a JSON array or named parameters. Use
181
189
  `--params-file FILE` when JSON is awkward to quote; `--params-file -` reads
182
190
  JSON from standard input.
183
191
 
192
+ ### Native MongoDB
193
+
194
+ MongoDB commands use official Extended JSON (EJSON), so BSON values survive the
195
+ CLI boundary:
196
+
197
+ ```bash
198
+ stql mongo query '{"operation":"find","collection":"users","filter":{"_id":{"$oid":"507f1f77bcf86cd799439011"}}}'
199
+ stql mongo exec '{"operation":"updateOne","collection":"users","filter":{"_id":{"$oid":"507f1f77bcf86cd799439011"}},"update":{"$set":{"seen_at":{"$date":"2026-01-01T00:00:00Z"}}}}'
200
+ stql mongo plan '{"operation":"deleteMany","collection":"users","filter":{"disabled":true}}' --allow-destructive
201
+ ```
202
+
203
+ The TypeScript equivalents are `mongoQuery(command)`, `mongoExec(command)`, and
204
+ `mongoPlan(command)`. Supported reads are `find` and `aggregate`; writes are
205
+ `insertOne`, `insertMany`, `updateOne`, `updateMany`, `replaceOne`, `deleteOne`,
206
+ and `deleteMany`. Result documents are JSON-safe, order-preserving EJSON: for example,
207
+ ObjectIds and dates appear as `{ "$oid": "..." }` and
208
+ `{ "$date": { "$numberLong": "..." } }`.
209
+
210
+ Empty update, replacement, or delete filters require `--allow-unbounded`;
211
+ deletes and replacements also require `--allow-destructive`. Mongo inspection accepts `collections`,
212
+ `collection`, `columns`, `indexes`, and `constraints` (`schema` and `table`
213
+ remain aliases shared with SQL drivers). MongoDB cache confidence is TTL-based:
214
+ external writes are not detected, so use `--cache bypass` for a fresh read.
215
+
216
+ ```ts
217
+ const result = await stateql.mongoQuery({
218
+ operation: "find",
219
+ collection: "users",
220
+ filter: { active: true },
221
+ options: { sort: { _id: 1 }, limit: 50 },
222
+ });
223
+ ```
184
224
  ### Output modes
185
225
 
186
226
  CLI output defaults to compact, one-line `agent` JSON. Successful responses
@@ -211,6 +251,7 @@ cancels active work.
211
251
  block StateQL's event loop.
212
252
  - PostgreSQL combines server-side `statement_timeout` with client deadlines.
213
253
  - MySQL deadlines destroy the active connection.
254
+ - MongoDB uses driver deadlines and closes stopped operations.
214
255
 
215
256
  A timed-out write may return `OUTCOME_UNKNOWN` when its commit status cannot be
216
257
  proven.
@@ -243,8 +284,8 @@ These caps bound persisted materialization; the independent deadline bounds
243
284
  execution time.
244
285
 
245
286
  Command history keeps the latest 10,000 entries per session. SQLite cache reuse
246
- also checks the database file signature. PostgreSQL and MySQL cache reuse is
247
- labeled `ttl_based` and is never authoritative.
287
+ also checks the database file signature. PostgreSQL, MySQL, and MongoDB cache
288
+ reuse is labeled `ttl_based` and is never authoritative.
248
289
 
249
290
  StateQL limits persisted result payloads to 256 MiB by default. When that quota
250
291
  is reached it removes the oldest unaliased results; aliases remain protected. A
@@ -303,6 +344,8 @@ SQLite supports `serializable`. PostgreSQL and MySQL also support
303
344
  `repeatable read`, `read committed`, and `read uncommitted`. Server reads run
304
345
  inside database-enforced read-only transactions. MySQL staged transactions
305
346
  reject DDL because MySQL implicitly commits those statements.
347
+ MongoDB transactions use `snapshot` isolation and require a replica set or
348
+ sharded deployment; standalone servers do not support them.
306
349
 
307
350
  ## Batch and pipes
308
351
 
@@ -345,9 +388,10 @@ stql batch commands.json
345
388
 
346
389
  Batch fields use snake case. Supported command names match CLI paths, such as
347
390
  `filter`, `transaction.begin`, `session.summary`, `alias.set`, `plan`, and
348
- `apply`. Batch filters use `where` for the predicate and may assign the derived
349
- result with `as`. Database commands may set `timeout_ms`; otherwise they use the
350
- 30-second default.
391
+ `apply`. Native MongoDB batches use `mongo.query`, `mongo.exec`, or `mongo.plan`
392
+ with the command object in `mongo`; the same cache, replay, idempotency, safety,
393
+ and timeout fields apply. Database commands may set `timeout_ms`; otherwise they
394
+ use the 30-second default.
351
395
 
352
396
  ## TypeScript library
353
397
 
@@ -440,13 +484,12 @@ safety and duplicate checks. Requests contain actor and session identity, the
440
484
  operation's effective read/write access, an abort signal, and sanitized
441
485
  connection metadata.
442
486
 
443
- Returned values must be complete PostgreSQL or MySQL URLs, or explicit
487
+ Returned values must be complete PostgreSQL, MySQL, or MongoDB URLs, or explicit
444
488
  `sqlite:` sources. StateQL validates the source and its stored driver before
445
- adapter construction and normalizes SQLite paths. Credential-bearing
446
- PostgreSQL and MySQL URLs are redacted before connection metadata is persisted
447
- and never enter history, snapshots, cache keys, or responses. SQLite paths
448
- remain persisted connection metadata, as they are for direct SQLite
449
- connections.
489
+ adapter construction and normalizes SQLite paths. Credential-bearing database
490
+ URLs are redacted before connection metadata is persisted and never enter
491
+ history, snapshots, cache keys, or responses. SQLite paths remain persisted
492
+ connection metadata, as they are for direct SQLite connections.
450
493
 
451
494
  Harnesses remain responsible for approval policy, binding lifetime, revocation,
452
495
  and keeping values out of their own logs and model-visible data.
@@ -26,6 +26,7 @@ export declare class AdapterWriteError extends Error {
26
26
  }
27
27
  export interface Adapter {
28
28
  readonly confidence: StateConfidence;
29
+ ping(): Promise<void>;
29
30
  read(sql: string, params: SqlParameters): Promise<ReadResult>;
30
31
  write(sql: string, params: SqlParameters): Promise<WriteResult>;
31
32
  writeBatch(operations: OperationRecord[], isolation: string): Promise<WriteResult[]>;
@@ -1,6 +1,7 @@
1
1
  import { fork } from "node:child_process";
2
2
  import { createConnection as createMySqlConnection, } from "mysql2";
3
3
  import { Client, types as pgTypes } from "pg";
4
+ import { StateQLError } from "./errors.js";
4
5
  import { isSqlParameters, parseJson, toJsonSafe } from "./util.js";
5
6
  export class AdapterExecutionError extends Error {
6
7
  reason;
@@ -36,13 +37,16 @@ export function createAdapterContext(timeoutMs, signal) {
36
37
  }
37
38
  export async function createAdapter(connection, context, input) {
38
39
  const { source } = input;
39
- if (connection.driver === "sqlite") {
40
- return new SQLiteAdapter(source, Boolean(connection.read_only), context);
40
+ switch (connection.driver) {
41
+ case "sqlite":
42
+ return new SQLiteAdapter(source, Boolean(connection.read_only), context);
43
+ case "postgres":
44
+ return new PostgresAdapter(source, Boolean(connection.read_only), context);
45
+ case "mysql":
46
+ return new MySqlAdapter(source, Boolean(connection.read_only), context);
47
+ case "mongodb":
48
+ throw new StateQLError("UNSUPPORTED_DRIVER", "MongoDB uses the native MongoDB adapter.");
41
49
  }
42
- if (connection.driver === "postgres") {
43
- return new PostgresAdapter(source, Boolean(connection.read_only), context);
44
- }
45
- return new MySqlAdapter(source, Boolean(connection.read_only), context);
46
50
  }
47
51
  class SQLiteAdapter {
48
52
  source;
@@ -85,6 +89,9 @@ class SQLiteAdapter {
85
89
  }
86
90
  });
87
91
  }
92
+ async ping() {
93
+ await this.read("SELECT 1", []);
94
+ }
88
95
  async read(sql, params) {
89
96
  return this.call("read", [sql, params], false, false);
90
97
  }
@@ -219,6 +226,9 @@ class PostgresAdapter {
219
226
  statement_timeout: timeout,
220
227
  });
221
228
  }
229
+ async ping() {
230
+ await this.read("SELECT 1", []);
231
+ }
222
232
  async read(sql, params) {
223
233
  await this.connect();
224
234
  await this.query("BEGIN READ ONLY", [], false);
@@ -440,6 +450,9 @@ class MySqlAdapter {
440
450
  this.readOnly = readOnly;
441
451
  this.context = context;
442
452
  }
453
+ async ping() {
454
+ await this.read("SELECT 1", []);
455
+ }
443
456
  async read(sql, params) {
444
457
  await this.query("START TRANSACTION READ ONLY", [], false, false);
445
458
  try {
package/dist/src/cli.js CHANGED
@@ -3,6 +3,7 @@ import { createReadStream, readFileSync } from "node:fs";
3
3
  import { extname, resolve } from "node:path";
4
4
  import { createInterface } from "node:readline";
5
5
  import { parseArgs } from "node:util";
6
+ import { BSON } from "mongodb";
6
7
  import { exitCodeFor } from "./errors.js";
7
8
  import { StateQL } from "./stateql.js";
8
9
  const parsed = parseArgs({
@@ -85,7 +86,10 @@ async function runSingle() {
85
86
  catch (error) {
86
87
  response = cliFailure(error);
87
88
  }
88
- print(response, mode, command ?? "");
89
+ const responseCommand = command === "mongo" && subcommand
90
+ ? `mongo.${subcommand}`
91
+ : command ?? "";
92
+ print(response, mode, responseCommand);
89
93
  if (!response.ok)
90
94
  process.exitCode = exitCodeFor(response.error.code);
91
95
  }
@@ -155,6 +159,8 @@ async function dispatch() {
155
159
  return dispatchProfile(subcommand, rest);
156
160
  case "session":
157
161
  return dispatchSession(subcommand, rest);
162
+ case "mongo":
163
+ return dispatchMongo(subcommand, rest);
158
164
  case "query":
159
165
  return stateql.query(sql, {
160
166
  params,
@@ -217,6 +223,41 @@ async function dispatch() {
217
223
  throw new Error(`Unknown command "${command}".`);
218
224
  }
219
225
  }
226
+ async function dispatchMongo(action, args) {
227
+ const payload = requireValue(args.join(" ").trim(), "MongoDB EJSON command");
228
+ switch (action) {
229
+ case "query":
230
+ return stateql.mongoQuery(parseMongoCommand(payload), {
231
+ cache: cacheMode(values.cache),
232
+ });
233
+ case "exec":
234
+ return stateql.mongoExec(parseMongoCommand(payload), {
235
+ replay: values.replay ?? false,
236
+ ...(values["idempotency-key"]
237
+ ? { idempotencyKey: values["idempotency-key"] }
238
+ : {}),
239
+ allowUnbounded: values["allow-unbounded"] ?? false,
240
+ allowDestructive: values["allow-destructive"] ?? false,
241
+ });
242
+ case "plan":
243
+ return stateql.mongoPlan(parseMongoCommand(payload), {
244
+ allowUnbounded: values["allow-unbounded"] ?? false,
245
+ ...(values["allow-destructive"]
246
+ ? { allowDestructive: true }
247
+ : {}),
248
+ });
249
+ default:
250
+ throw new Error(`Unknown MongoDB command "${action ?? ""}".`);
251
+ }
252
+ }
253
+ function parseMongoCommand(value) {
254
+ try {
255
+ return BSON.EJSON.parse(value, { relaxed: false });
256
+ }
257
+ catch {
258
+ throw new Error("Invalid MongoDB EJSON command.");
259
+ }
260
+ }
220
261
  async function dispatchSession(action, args) {
221
262
  switch (action) {
222
263
  case "start":
@@ -427,6 +468,7 @@ function toAgentResponse(result, currentCommand) {
427
468
  if (handle && handleKey)
428
469
  delete data[handleKey];
429
470
  if ((currentCommand === "query" ||
471
+ currentCommand === "mongo.query" ||
430
472
  currentCommand === "filter" ||
431
473
  currentCommand === "show") &&
432
474
  typeof data.rows === "number" &&
@@ -469,6 +511,7 @@ function toAgentResponse(result, currentCommand) {
469
511
  function primaryHandleKey(currentCommand) {
470
512
  const keys = {
471
513
  query: "result_id",
514
+ "mongo.query": "result_id",
472
515
  filter: "result_id",
473
516
  show: "result_id",
474
517
  rows: "result_id",
@@ -478,9 +521,11 @@ function primaryHandleKey(currentCommand) {
478
521
  alias: "result_id",
479
522
  "alias.set": "result_id",
480
523
  exec: "operation_id",
524
+ "mongo.exec": "operation_id",
481
525
  receipt: "operation_id",
482
526
  apply: "operation_id",
483
527
  plan: "plan_id",
528
+ "mongo.plan": "plan_id",
484
529
  connect: "connection_id",
485
530
  transaction: "transaction_id",
486
531
  "transaction.begin": "transaction_id",
@@ -535,8 +580,9 @@ Commands:
535
580
  profile add|list|show|remove
536
581
  session start|list|show|summary|close
537
582
  query, filter, exec, show, rows, count, columns, export
583
+ mongo query|exec|plan '<EJSON command>'
538
584
  alias set
539
- inspect schema|table|columns|indexes|constraints
585
+ inspect schema|table|collection|collections|columns|indexes|constraints
540
586
  transaction begin|status|commit|rollback
541
587
  plan, apply, history, receipt, doctor, purge, capabilities
542
588
  batch [file.json|file.jsonl|-]
@@ -2,6 +2,7 @@ import type { ConnectionRecord } from "./store.js";
2
2
  import type { Driver, StateConfidence } from "./types.js";
3
3
  export declare function databaseIdentity(connection: ConnectionRecord): unknown;
4
4
  export declare function detectDriver(target: string): Driver;
5
+ export declare function mongoDatabaseName(target: string): string;
5
6
  export declare function credentialSource(value: string, expectedDriver?: Driver): {
6
7
  driver: Driver;
7
8
  source: string;
@@ -13,16 +13,41 @@ export function detectDriver(target) {
13
13
  return "postgres";
14
14
  if (/^mysql:\/\//i.test(target))
15
15
  return "mysql";
16
+ if (/^mongodb(?:\+srv)?:\/\//i.test(target))
17
+ return "mongodb";
16
18
  if (/^[a-z][a-z\d+.-]*:\/\//i.test(target)) {
17
- throw new StateQLError("UNSUPPORTED_DRIVER", "Only MySQL, PostgreSQL, and SQLite are supported.");
19
+ throw new StateQLError("UNSUPPORTED_DRIVER", "Only MongoDB, MySQL, PostgreSQL, and SQLite are supported.");
18
20
  }
19
21
  return "sqlite";
20
22
  }
23
+ export function mongoDatabaseName(target) {
24
+ let url;
25
+ try {
26
+ url = new URL(target);
27
+ }
28
+ catch {
29
+ throw new StateQLError("INVALID_COMMAND", "Invalid MongoDB URL.");
30
+ }
31
+ if (!["mongodb:", "mongodb+srv:"].includes(url.protocol.toLowerCase()) ||
32
+ !url.hostname) {
33
+ throw new StateQLError("INVALID_COMMAND", "Invalid MongoDB URL.");
34
+ }
35
+ try {
36
+ const database = decodeURIComponent(url.pathname.replace(/^\//, ""));
37
+ if (database && !database.includes("/") && !database.includes("\0")) {
38
+ return database;
39
+ }
40
+ }
41
+ catch {
42
+ // Report malformed escaping as an invalid explicit database name.
43
+ }
44
+ throw new StateQLError("INVALID_COMMAND", "MongoDB URL must include an explicit database name.");
45
+ }
21
46
  export function credentialSource(value, expectedDriver) {
22
47
  const explicitSqlite = /^sqlite:(?!\/\/)/i.test(value);
23
48
  const driver = explicitSqlite ? "sqlite" : detectDriver(value);
24
49
  if (driver === "sqlite" && (!explicitSqlite || value.length === 7)) {
25
- throw new StateQLError("INVALID_COMMAND", "Secret environment variable must contain a complete PostgreSQL/MySQL URL or an explicit sqlite: source.", {
50
+ throw new StateQLError("INVALID_COMMAND", "Secret environment variable must contain a complete PostgreSQL/MySQL URL or an explicit sqlite: source; MongoDB URLs are also supported.", {
26
51
  suggestedAction: "Store the full database URL, or prefix an SQLite path with sqlite:.",
27
52
  });
28
53
  }
@@ -54,7 +79,8 @@ export function normalizeSqliteSource(target) {
54
79
  export function databaseUrlHasSecret(target) {
55
80
  try {
56
81
  const url = new URL(target);
57
- return (Boolean(url.password) ||
82
+ return (Boolean(url.username) ||
83
+ Boolean(url.password) ||
58
84
  [...url.searchParams.keys()].some((key) => /pass|token|secret|private[_-]?key|api[_-]?key/i.test(key)));
59
85
  }
60
86
  catch {
@@ -1,4 +1,4 @@
1
1
  export { StateQL } from "./stateql.js";
2
2
  export { CredentialResolutionError, StateQLError, exitCodeFor, } from "./errors.js";
3
3
  export type { CredentialResolutionFailure } from "./errors.js";
4
- export type { ActorData, ActorLinkData, ActorResolutionData, ActorsData, ActorUnlinkData, AliasData, ApplyData, BatchCommand, BatchCommandName, BatchOptions, CapabilitiesData, CloseSessionData, Column, ColumnsData, CommitTransactionData, ConnectOptions, ConnectionData, CountData, CredentialAccess, CredentialOperation, CredentialRequest, CredentialResolver, DisconnectData, DoctorData, Driver, ExecData, ExecOptions, ExecutionOptions, ExportData, Failure, FilterOptions, HistoryData, HistoryEntry, OperationData, PlanData, PlanOptions, ProfileData, ProfileOptions, ProfilesData, PurgeData, QueryOptions, RecentOperationData, RecentResultData, RemovedProfileData, Response, ResultData, RollbackTransactionData, Row, RowsData, RowsOptions, SqlParameters, StateQLActorOptions, StateQLOptions, StateConfidence, StateQLSnapshot, StatusConnectionData, StatusData, Success, SessionData, SessionListItem, SessionsData, SessionSummaryData, TransactionData, TransactionReferenceData, Warning, } from "./types.js";
4
+ export type { ActorData, ActorLinkData, ActorResolutionData, ActorsData, ActorUnlinkData, AliasData, ApplyData, BatchCommand, BatchCommandName, BatchOptions, CapabilitiesData, CloseSessionData, Column, ColumnsData, CommitTransactionData, ConnectOptions, ConnectionData, CountData, CredentialAccess, CredentialOperation, CredentialRequest, CredentialResolver, DisconnectData, DoctorData, Driver, ExecData, ExecOptions, ExecutionOptions, ExportData, Failure, FilterOptions, HistoryData, HistoryEntry, MongoAggregateOptions, MongoDocument, MongoFindOptions, MongoMutationOptions, MongoExecOptions, MongoPlanOptions, MongoQueryOptions, MongoReadCommand, MongoWriteCommand, MongoWriteOutcome, OperationData, PlanData, PlanOptions, ProfileData, ProfileOptions, ProfilesData, PurgeData, QueryOptions, RecentOperationData, RecentResultData, RemovedProfileData, Response, ResultData, RollbackTransactionData, Row, RowsData, RowsOptions, SqlParameters, SqlDriver, StateQLActorOptions, StateQLOptions, StateConfidence, StateQLSnapshot, StatusConnectionData, StatusData, Success, SessionData, SessionListItem, SessionsData, SessionSummaryData, TransactionData, TransactionReferenceData, Warning, } from "./types.js";
@@ -55,6 +55,15 @@ const MIGRATIONS = [
55
55
  requireColumns(db, "history", ["sql"]);
56
56
  },
57
57
  },
58
+ {
59
+ name: "operation_outcomes_v1",
60
+ apply(db) {
61
+ addColumn(db, "operations", "outcome_json", "TEXT");
62
+ },
63
+ validate(db) {
64
+ requireColumns(db, "operations", ["outcome_json"]);
65
+ },
66
+ },
58
67
  ];
59
68
  export function runMigrations(db, now) {
60
69
  db.exec(`
@@ -169,6 +178,7 @@ function createInitialSchema(db) {
169
178
  idempotency_key TEXT,
170
179
  state_version_before TEXT NOT NULL,
171
180
  state_version_after TEXT,
181
+ outcome_json TEXT,
172
182
  created_at TEXT NOT NULL
173
183
  );
174
184
  CREATE INDEX IF NOT EXISTS operations_fingerprint
@@ -0,0 +1,48 @@
1
+ import { type AdapterContext } from "./adapters.js";
2
+ import type { ConnectionRecord } from "./store.js";
3
+ import type { Column, MongoReadCommand, MongoWriteCommand, MongoWriteOutcome, Row } from "./types.js";
4
+ interface MongoReadResult {
5
+ rows: Row[];
6
+ columns: Column[];
7
+ }
8
+ interface MongoWriteResult {
9
+ affectedRows: number;
10
+ outcome: MongoWriteOutcome;
11
+ }
12
+ interface MongoWriteSafety {
13
+ unbounded: boolean;
14
+ destructive: boolean;
15
+ }
16
+ export declare function validateMongoReadCommand(value: unknown): MongoReadCommand;
17
+ export declare function validateMongoWriteCommand(value: unknown): MongoWriteCommand;
18
+ export declare function analyzeMongoWriteSafety(command: MongoWriteCommand): MongoWriteSafety;
19
+ /** Deterministic EJSON preserves BSON types and property order. */
20
+ export declare function serializeMongoCommand(command: MongoReadCommand | MongoWriteCommand): string;
21
+ export declare function deserializeMongoWriteCommand(value: string): MongoWriteCommand;
22
+ export declare class MongoAdapter {
23
+ private readonly context;
24
+ readonly confidence: "ttl_based";
25
+ private readonly client;
26
+ private readonly databaseName;
27
+ private readonly readOnly;
28
+ private connected;
29
+ private closed;
30
+ private connecting?;
31
+ constructor(connection: ConnectionRecord, context: AdapterContext, input: {
32
+ source: string;
33
+ });
34
+ ping(): Promise<void>;
35
+ signature(): Promise<string>;
36
+ read(command: MongoReadCommand, maxRows: number): Promise<MongoReadResult>;
37
+ write(command: MongoWriteCommand): Promise<MongoWriteResult>;
38
+ writeBatch(commands: MongoWriteCommand[], isolation: string): Promise<MongoWriteResult[]>;
39
+ inspect(kind: string, name?: string): Promise<unknown>;
40
+ close(): Promise<void>;
41
+ private connect;
42
+ private executeWrite;
43
+ private requireCollection;
44
+ private sampleColumns;
45
+ private collectionIndexes;
46
+ private stop;
47
+ }
48
+ export {};