@fadhilp/stateql 0.5.4 → 0.7.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.
@@ -1,5 +1,5 @@
1
1
  import { DatabaseSync } from "node:sqlite";
2
- import type { Column, Driver, Row, SqlParameters, StateConfidence } from "./types.js";
2
+ import type { Column, CommandOrigin, Driver, MongoWriteOutcome, Row, SqlParameters, StateConfidence } from "./types.js";
3
3
  export interface SessionRecord {
4
4
  id: string;
5
5
  name: string;
@@ -61,6 +61,7 @@ export interface OperationRecord {
61
61
  idempotency_key: string | null;
62
62
  state_version_before: string;
63
63
  state_version_after: string | null;
64
+ outcome_json: string | null;
64
65
  created_at: string;
65
66
  }
66
67
  export interface TransactionRecord {
@@ -97,6 +98,7 @@ export interface HistoryRecord {
97
98
  timestamp: string;
98
99
  session_id: string;
99
100
  actor_id: string;
101
+ origin: CommandOrigin;
100
102
  command: string;
101
103
  sql: string | null;
102
104
  handle: string | null;
@@ -211,7 +213,7 @@ export declare class StateStore {
211
213
  previous?: OperationRecord;
212
214
  denied?: "membership" | "transaction";
213
215
  };
214
- finishOperation(operationId: string, affectedRows: number, stateVersion: string): OperationRecord;
216
+ finishOperation(operationId: string, affectedRows: number, stateVersion: string, outcome?: MongoWriteOutcome): OperationRecord;
215
217
  failOperation(operationId: string): void;
216
218
  markOperationOutcomeUnknown(operationId: string): void;
217
219
  createTransaction(input: {
@@ -235,6 +237,7 @@ export declare class StateStore {
235
237
  operations: Array<{
236
238
  id: string;
237
239
  affectedRows: number;
240
+ outcome?: MongoWriteOutcome;
238
241
  }>;
239
242
  }): string;
240
243
  savePlan(input: {
@@ -260,6 +263,7 @@ export declare class StateStore {
260
263
  operationId: string;
261
264
  connectionId: string;
262
265
  affectedRows: number;
266
+ outcome?: MongoWriteOutcome;
263
267
  }): {
264
268
  operation: OperationRecord;
265
269
  stateVersion: string;
@@ -267,6 +271,7 @@ export declare class StateStore {
267
271
  addHistory(input: {
268
272
  sessionId: string;
269
273
  actorId: string;
274
+ origin?: CommandOrigin;
270
275
  command: string;
271
276
  sql?: string;
272
277
  handle?: string;
@@ -276,7 +281,7 @@ export declare class StateStore {
276
281
  errorCode?: string;
277
282
  id?: string;
278
283
  }): HistoryRecord;
279
- history(sessionId: string, limit: number): HistoryRecord[];
284
+ history(sessionId: string, limit: number, origin?: CommandOrigin): HistoryRecord[];
280
285
  recentOperations(sessionId: string, limit: number): OperationRecord[];
281
286
  knownResults(sessionId: string, limit: number): Array<ResultRecord & {
282
287
  alias: string | null;
package/dist/src/store.js CHANGED
@@ -480,12 +480,13 @@ export class StateStore {
480
480
  throw error;
481
481
  }
482
482
  }
483
- finishOperation(operationId, affectedRows, stateVersion) {
483
+ finishOperation(operationId, affectedRows, stateVersion, outcome) {
484
484
  this.db
485
485
  .prepare(`UPDATE operations
486
- SET status = 'committed', affected_rows = ?, state_version_after = ?
486
+ SET status = 'committed', affected_rows = ?, state_version_after = ?,
487
+ outcome_json = ?
487
488
  WHERE id = ?`)
488
- .run(affectedRows, stateVersion, operationId);
489
+ .run(affectedRows, stateVersion, outcomeJson(outcome), operationId);
489
490
  return this.getOperation(operationId);
490
491
  }
491
492
  failOperation(operationId) {
@@ -695,9 +696,10 @@ export class StateStore {
695
696
  stateVersion = `sv_${row.version}`;
696
697
  this.db
697
698
  .prepare(`UPDATE operations
698
- SET status = 'committed', affected_rows = ?, state_version_after = ?
699
+ SET status = 'committed', affected_rows = ?, state_version_after = ?,
700
+ outcome_json = ?
699
701
  WHERE id = ?`)
700
- .run(operation.affectedRows, stateVersion, operation.id);
702
+ .run(operation.affectedRows, stateVersion, outcomeJson(operation.outcome), operation.id);
701
703
  }
702
704
  this.db
703
705
  .prepare(`UPDATE transactions
@@ -772,9 +774,10 @@ export class StateStore {
772
774
  const stateVersion = `sv_${row.version}`;
773
775
  this.db
774
776
  .prepare(`UPDATE operations
775
- SET status = 'committed', affected_rows = ?, state_version_after = ?
777
+ SET status = 'committed', affected_rows = ?, state_version_after = ?,
778
+ outcome_json = ?
776
779
  WHERE id = ?`)
777
- .run(input.affectedRows, stateVersion, input.operationId);
780
+ .run(input.affectedRows, stateVersion, outcomeJson(input.outcome), input.operationId);
778
781
  this.db
779
782
  .prepare(`UPDATE plans SET applied_operation_id = ?, claim_token = NULL
780
783
  WHERE id = ? AND claim_token = ?`)
@@ -792,10 +795,10 @@ export class StateStore {
792
795
  const id = input.id ?? this.nextId("cmd");
793
796
  this.db
794
797
  .prepare(`INSERT INTO history
795
- (id, timestamp, session_id, actor_id, command, sql, handle, executed,
796
- cached, success, error_code)
797
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
798
- .run(id, this.now().toISOString(), input.sessionId, input.actorId, input.command, boundedHistorySql(input.sql), input.handle ?? null, input.executed ? 1 : 0, input.cached ? 1 : 0, input.success ? 1 : 0, input.errorCode ?? null);
798
+ (id, timestamp, session_id, actor_id, origin, command, sql, handle,
799
+ executed, cached, success, error_code)
800
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
801
+ .run(id, this.now().toISOString(), input.sessionId, input.actorId, input.origin ?? "legacy", input.command, boundedHistorySql(input.sql), input.handle ?? null, input.executed ? 1 : 0, input.cached ? 1 : 0, input.success ? 1 : 0, input.errorCode ?? null);
799
802
  this.db
800
803
  .prepare(`DELETE FROM history
801
804
  WHERE rowid IN (
@@ -809,13 +812,13 @@ export class StateStore {
809
812
  .prepare("SELECT * FROM history WHERE id = ?")
810
813
  .get(id);
811
814
  }
812
- history(sessionId, limit) {
815
+ history(sessionId, limit, origin) {
813
816
  return this.db
814
817
  .prepare(`SELECT * FROM history
815
- WHERE session_id = ?
818
+ WHERE session_id = ?${origin === undefined ? "" : " AND origin = ?"}
816
819
  ORDER BY rowid DESC
817
820
  LIMIT ?`)
818
- .all(sessionId, limit);
821
+ .all(...(origin === undefined ? [sessionId, limit] : [sessionId, origin, limit]));
819
822
  }
820
823
  recentOperations(sessionId, limit) {
821
824
  return this.db
@@ -1011,6 +1014,9 @@ export class StateStore {
1011
1014
  }
1012
1015
  }
1013
1016
  }
1017
+ function outcomeJson(outcome) {
1018
+ return outcome === undefined ? null : JSON.stringify(toJsonSafe(outcome));
1019
+ }
1014
1020
  function boundedHistorySql(sql) {
1015
1021
  if (sql === undefined)
1016
1022
  return null;
@@ -1,4 +1,11 @@
1
- export type Driver = "sqlite" | "postgres" | "mysql";
1
+ export type SqlDriver = "sqlite" | "postgres" | "mysql";
2
+ export type Driver = SqlDriver | "mongodb";
3
+ export type CommandOrigin = "legacy" | "user" | "model" | "system" | "api";
4
+ /** Trusted host metadata for one executeCommand call; never part of BatchCommand input. */
5
+ export interface CommandExecutionContext {
6
+ signal?: AbortSignal;
7
+ origin?: CommandOrigin;
8
+ }
2
9
  export type CredentialAccess = "read" | "write";
3
10
  export type CredentialOperation = "connect" | "query" | "inspect" | "plan" | "exec" | "apply" | "transaction.commit";
4
11
  export interface CredentialRequest {
@@ -63,6 +70,7 @@ export interface HistoryEntry {
63
70
  timestamp: string;
64
71
  session_id: string;
65
72
  actor_id: string;
73
+ origin: CommandOrigin;
66
74
  command: string;
67
75
  sql: string | null;
68
76
  handle: string | null;
@@ -108,10 +116,84 @@ export interface StateQLSnapshot {
108
116
  history: HistoryEntry[];
109
117
  }
110
118
  export type SqlParameters = unknown[] | Record<string, unknown>;
119
+ export type MongoDocument = Record<string, unknown>;
120
+ export interface MongoFindOptions {
121
+ projection?: MongoDocument;
122
+ sort?: MongoDocument | Array<[string, 1 | -1]>;
123
+ skip?: number;
124
+ limit?: number;
125
+ hint?: string | MongoDocument;
126
+ collation?: MongoDocument;
127
+ }
128
+ export interface MongoAggregateOptions {
129
+ allowDiskUse?: boolean;
130
+ hint?: string | MongoDocument;
131
+ collation?: MongoDocument;
132
+ }
133
+ export interface MongoMutationOptions {
134
+ upsert?: boolean;
135
+ collation?: MongoDocument;
136
+ hint?: string | MongoDocument;
137
+ }
138
+ export type MongoReadCommand = {
139
+ operation: "find";
140
+ collection: string;
141
+ filter?: MongoDocument;
142
+ options?: MongoFindOptions;
143
+ } | {
144
+ operation: "aggregate";
145
+ collection: string;
146
+ pipeline: MongoDocument[];
147
+ options?: MongoAggregateOptions;
148
+ };
149
+ export type MongoWriteCommand = {
150
+ operation: "insertOne";
151
+ collection: string;
152
+ document: MongoDocument;
153
+ options?: Record<string, never>;
154
+ } | {
155
+ operation: "insertMany";
156
+ collection: string;
157
+ documents: MongoDocument[];
158
+ options?: {
159
+ ordered?: boolean;
160
+ };
161
+ } | {
162
+ operation: "updateOne" | "updateMany";
163
+ collection: string;
164
+ filter: MongoDocument;
165
+ update: MongoDocument | MongoDocument[];
166
+ options?: MongoMutationOptions;
167
+ } | {
168
+ operation: "replaceOne";
169
+ collection: string;
170
+ filter: MongoDocument;
171
+ replacement: MongoDocument;
172
+ options?: MongoMutationOptions;
173
+ } | {
174
+ operation: "deleteOne" | "deleteMany";
175
+ collection: string;
176
+ filter: MongoDocument;
177
+ options?: Omit<MongoMutationOptions, "upsert">;
178
+ };
179
+ export interface MongoWriteOutcome {
180
+ acknowledged: boolean;
181
+ inserted_id?: unknown;
182
+ inserted_ids?: unknown[];
183
+ inserted_count?: number;
184
+ matched_count?: number;
185
+ modified_count?: number;
186
+ upserted_count?: number;
187
+ upserted_id?: unknown;
188
+ deleted_count?: number;
189
+ }
111
190
  export interface ExecutionOptions {
112
191
  timeoutMs?: number;
113
192
  signal?: AbortSignal;
114
193
  }
194
+ export interface HistoryOptions {
195
+ origin?: CommandOrigin;
196
+ }
115
197
  export interface StateQLOptions extends ExecutionOptions {
116
198
  home?: string;
117
199
  session?: string;
@@ -133,6 +215,9 @@ export interface QueryOptions extends ExecutionOptions {
133
215
  params?: SqlParameters;
134
216
  cache?: "auto" | "bypass" | "require";
135
217
  }
218
+ export interface MongoQueryOptions extends ExecutionOptions {
219
+ cache?: "auto" | "bypass" | "require";
220
+ }
136
221
  export interface FilterOptions {
137
222
  params?: SqlParameters;
138
223
  }
@@ -143,6 +228,12 @@ export interface ExecOptions extends ExecutionOptions {
143
228
  allowUnbounded?: boolean;
144
229
  allowDestructive?: boolean;
145
230
  }
231
+ export interface MongoExecOptions extends ExecutionOptions {
232
+ replay?: boolean;
233
+ idempotencyKey?: string;
234
+ allowUnbounded?: boolean;
235
+ allowDestructive?: boolean;
236
+ }
146
237
  export interface ConnectOptions extends ExecutionOptions {
147
238
  name?: string;
148
239
  readOnly?: boolean;
@@ -162,7 +253,11 @@ export interface PlanOptions extends ExecutionOptions {
162
253
  allowUnbounded?: boolean;
163
254
  allowDestructive?: boolean;
164
255
  }
165
- export type BatchCommandName = "connect" | "disconnect" | "status" | "profile.add" | "profile.list" | "profile.show" | "profile.remove" | "session.start" | "session.list" | "session.show" | "session.summary" | "session.close" | "query" | "filter" | "exec" | "show" | "rows" | "count" | "columns" | "alias.set" | "inspect" | "transaction.begin" | "transaction.status" | "transaction.commit" | "transaction.rollback" | "plan" | "apply" | "history" | "receipt" | "doctor" | "purge" | "capabilities";
256
+ export interface MongoPlanOptions extends ExecutionOptions {
257
+ allowUnbounded?: boolean;
258
+ allowDestructive?: boolean;
259
+ }
260
+ export type BatchCommandName = "connect" | "disconnect" | "status" | "profile.add" | "profile.list" | "profile.show" | "profile.remove" | "session.start" | "session.list" | "session.show" | "session.summary" | "session.close" | "query" | "filter" | "exec" | "show" | "rows" | "count" | "columns" | "alias.set" | "inspect" | "transaction.begin" | "transaction.status" | "transaction.commit" | "transaction.rollback" | "plan" | "mongo.query" | "mongo.exec" | "mongo.plan" | "apply" | "history" | "receipt" | "doctor" | "purge" | "capabilities";
166
261
  export interface BatchCommand {
167
262
  command: BatchCommandName;
168
263
  target?: string;
@@ -174,6 +269,7 @@ export interface BatchCommand {
174
269
  kind?: string;
175
270
  table?: string;
176
271
  params?: SqlParameters;
272
+ mongo?: MongoReadCommand | MongoWriteCommand;
177
273
  cache?: "auto" | "bypass" | "require";
178
274
  read_only?: boolean;
179
275
  secret_env?: string;
@@ -186,11 +282,14 @@ export interface BatchCommand {
186
282
  limit?: number;
187
283
  isolation?: string;
188
284
  timeout_ms?: number;
285
+ /** Retrieval filter for the history command; does not attribute this command. */
286
+ history_origin?: CommandOrigin;
189
287
  scope?: "expired" | "results" | "history" | "all";
190
288
  }
191
289
  export interface BatchOptions {
192
290
  continueOnError?: boolean;
193
291
  maxCommands?: number;
292
+ executionContext?: CommandExecutionContext;
194
293
  }
195
294
  export interface Column {
196
295
  name: string;
@@ -355,6 +454,7 @@ export interface OperationData {
355
454
  state_version_before: string;
356
455
  state_version_after: string | null;
357
456
  replay_of?: string;
457
+ outcome?: MongoWriteOutcome;
358
458
  }
359
459
  export interface ExecData extends OperationData {
360
460
  duplicate?: boolean;
@@ -421,6 +521,7 @@ export interface PurgeData {
421
521
  export interface CapabilitiesData {
422
522
  drivers: Driver[];
423
523
  features: Record<string, boolean>;
524
+ driver_features?: Partial<Record<Driver, Record<string, boolean>>>;
424
525
  }
425
526
  export interface RemovedProfileData {
426
527
  profile: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fadhilp/stateql",
3
- "version": "0.5.4",
3
+ "version": "0.7.0",
4
4
  "description": "Stateful, agent-oriented database CLI for safe result reuse",
5
5
  "repository": {
6
6
  "type": "git",
@@ -25,7 +25,7 @@
25
25
  ],
26
26
  "scripts": {
27
27
  "build": "tsc -p tsconfig.json",
28
- "test": "npm run build && node --test dist/test/cli.test.js dist/test/credential.test.js dist/test/mysql.test.js dist/test/postgres.test.js dist/test/query.test.js dist/test/sqlite.test.js dist/test/store.test.js dist/test/terminal.test.js dist/test/transaction.test.js dist/test/write.test.js",
28
+ "test": "npm run build && node --test dist/test/cli.test.js dist/test/credential.test.js dist/test/mongodb.test.js dist/test/mysql.test.js dist/test/postgres.test.js dist/test/query.test.js dist/test/sqlite.test.js dist/test/store.test.js dist/test/terminal.test.js dist/test/transaction.test.js dist/test/write.test.js",
29
29
  "release": "npm version",
30
30
  "version": "npm install",
31
31
  "prepack": "npm test"
@@ -44,6 +44,7 @@
44
44
  "node": ">=22.16"
45
45
  },
46
46
  "dependencies": {
47
+ "mongodb": "^6.21.0",
47
48
  "mysql2": "^3.23.1",
48
49
  "node-sql-parser": "^5.4.0",
49
50
  "pg": "^8.16.3"