@fadhilp/stateql 0.1.2 → 0.2.2

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.
@@ -108,6 +108,7 @@ export declare class StateStore {
108
108
  ensureSession(name?: string): SessionRecord;
109
109
  createSession(name: string): SessionRecord;
110
110
  getSession(idOrName: string): SessionRecord | undefined;
111
+ getSessionByName(name: string): SessionRecord | undefined;
111
112
  listSessions(): SessionRecord[];
112
113
  closeSession(sessionId: string): void;
113
114
  addProfile(input: {
@@ -240,6 +241,7 @@ export declare class StateStore {
240
241
  knownResults(sessionId: string, limit: number): Array<ResultRecord & {
241
242
  alias: string | null;
242
243
  }>;
244
+ private deleteExpiredData;
243
245
  private recoverStaleCommittingTransactions;
244
246
  private migrate;
245
247
  }
package/dist/src/store.js CHANGED
@@ -16,6 +16,7 @@ export class StateStore {
16
16
  this.db.exec("PRAGMA foreign_keys = ON");
17
17
  this.migrate();
18
18
  this.recoverStaleCommittingTransactions();
19
+ this.deleteExpiredData();
19
20
  }
20
21
  close() {
21
22
  this.db.close();
@@ -30,10 +31,20 @@ export class StateStore {
30
31
  return `${prefix}_${row.value}`;
31
32
  }
32
33
  ensureSession(name = "default") {
33
- const existing = this.getSession(name);
34
+ const existing = this.getSessionByName(name);
34
35
  if (existing)
35
36
  return existing;
36
- return this.createSession(name);
37
+ const closed = this.db
38
+ .prepare("SELECT id FROM sessions WHERE name = ? LIMIT 1")
39
+ .get(name);
40
+ if (!closed)
41
+ return this.createSession(name);
42
+ this.db
43
+ .prepare(`UPDATE sessions
44
+ SET status = 'active', active_transaction_id = NULL, updated_at = ?
45
+ WHERE id = ?`)
46
+ .run(this.now().toISOString(), closed.id);
47
+ return this.getSessionByName(name);
37
48
  }
38
49
  createSession(name) {
39
50
  const timestamp = this.now().toISOString();
@@ -52,6 +63,11 @@ export class StateStore {
52
63
  LIMIT 1`)
53
64
  .get(idOrName, idOrName);
54
65
  }
66
+ getSessionByName(name) {
67
+ return this.db
68
+ .prepare("SELECT * FROM sessions WHERE name = ? AND status = 'active' LIMIT 1")
69
+ .get(name);
70
+ }
55
71
  listSessions() {
56
72
  return this.db
57
73
  .prepare("SELECT * FROM sessions ORDER BY created_at")
@@ -462,6 +478,25 @@ export class StateStore {
462
478
  LIMIT ?`)
463
479
  .all(sessionId, limit);
464
480
  }
481
+ deleteExpiredData() {
482
+ const timestamp = this.now().toISOString();
483
+ this.db.exec("BEGIN IMMEDIATE");
484
+ try {
485
+ this.db
486
+ .prepare(`DELETE FROM aliases
487
+ WHERE result_id IN (
488
+ SELECT id FROM results WHERE expires_at <= ?
489
+ )`)
490
+ .run(timestamp);
491
+ this.db.prepare("DELETE FROM results WHERE expires_at <= ?").run(timestamp);
492
+ this.db.prepare("DELETE FROM plans WHERE expires_at <= ?").run(timestamp);
493
+ this.db.exec("COMMIT");
494
+ }
495
+ catch (error) {
496
+ this.db.exec("ROLLBACK");
497
+ throw error;
498
+ }
499
+ }
465
500
  recoverStaleCommittingTransactions() {
466
501
  const timestamp = this.now().toISOString();
467
502
  const cutoff = new Date(this.now().getTime() - 5 * 60_000).toISOString();
@@ -1,4 +1,4 @@
1
- export type Driver = "sqlite" | "postgres";
1
+ export type Driver = "sqlite" | "postgres" | "mysql";
2
2
  export type StateConfidence = "authoritative" | "transaction_snapshot" | "database_reported" | "local" | "ttl_based" | "unknown";
3
3
  export interface Warning {
4
4
  code: string;
@@ -33,8 +33,56 @@ export interface Failure {
33
33
  meta: ResponseMeta;
34
34
  }
35
35
  export type Response<T> = Success<T> | Failure;
36
+ export interface HistoryEntry {
37
+ command_id: string;
38
+ timestamp: string;
39
+ session_id: string;
40
+ command: string;
41
+ handle: string | null;
42
+ executed: boolean;
43
+ cached: boolean;
44
+ success: boolean;
45
+ error_code: string | null;
46
+ }
47
+ export interface StateQLSnapshot {
48
+ session: {
49
+ session_id: string;
50
+ name: string;
51
+ status: string;
52
+ };
53
+ connection: {
54
+ connection_id: string;
55
+ name: string;
56
+ status: "connected";
57
+ driver: Driver;
58
+ database: string;
59
+ read_only: boolean;
60
+ } | null;
61
+ transaction: {
62
+ transaction_id: string;
63
+ state: string;
64
+ } | null;
65
+ state_version: string | null;
66
+ state_confidence: StateConfidence | null;
67
+ recent_results: Array<{
68
+ alias: string | null;
69
+ handle: string;
70
+ rows: number;
71
+ }>;
72
+ recent_operations: Array<{
73
+ handle: string;
74
+ type: string;
75
+ affected_rows: number | null;
76
+ status: string;
77
+ }>;
78
+ history: HistoryEntry[];
79
+ }
36
80
  export type SqlParameters = unknown[] | Record<string, unknown>;
37
- export interface StateQLOptions {
81
+ export interface ExecutionOptions {
82
+ timeoutMs?: number;
83
+ signal?: AbortSignal;
84
+ }
85
+ export interface StateQLOptions extends ExecutionOptions {
38
86
  home?: string;
39
87
  session?: string;
40
88
  previewRows?: number;
@@ -42,23 +90,24 @@ export interface StateQLOptions {
42
90
  resultTtlSeconds?: number;
43
91
  maxCellCharacters?: number;
44
92
  maxResultRows?: number;
93
+ maxResultBytes?: number;
45
94
  now?: () => Date;
46
95
  }
47
- export interface QueryOptions {
96
+ export interface QueryOptions extends ExecutionOptions {
48
97
  params?: SqlParameters;
49
98
  cache?: "auto" | "bypass" | "require";
50
99
  }
51
100
  export interface FilterOptions {
52
101
  params?: SqlParameters;
53
102
  }
54
- export interface ExecOptions {
103
+ export interface ExecOptions extends ExecutionOptions {
55
104
  params?: SqlParameters;
56
105
  replay?: boolean;
57
106
  idempotencyKey?: string;
58
107
  allowUnbounded?: boolean;
59
108
  allowDestructive?: boolean;
60
109
  }
61
- export interface ConnectOptions {
110
+ export interface ConnectOptions extends ExecutionOptions {
62
111
  name?: string;
63
112
  readOnly?: boolean;
64
113
  secretEnv?: string;
@@ -72,7 +121,7 @@ export interface RowsOptions {
72
121
  offset?: number;
73
122
  limit?: number;
74
123
  }
75
- export interface PlanOptions {
124
+ export interface PlanOptions extends ExecutionOptions {
76
125
  params?: SqlParameters;
77
126
  allowUnbounded?: boolean;
78
127
  allowDestructive?: boolean;
@@ -100,6 +149,7 @@ export interface BatchCommand {
100
149
  offset?: number;
101
150
  limit?: number;
102
151
  isolation?: string;
152
+ timeout_ms?: number;
103
153
  }
104
154
  export interface BatchOptions {
105
155
  continueOnError?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fadhilp/stateql",
3
- "version": "0.1.2",
3
+ "version": "0.2.2",
4
4
  "description": "Stateful, agent-oriented database CLI for safe result reuse",
5
5
  "repository": {
6
6
  "type": "git",
@@ -25,11 +25,12 @@
25
25
  ],
26
26
  "scripts": {
27
27
  "build": "tsc -p tsconfig.json",
28
- "test": "npm run build && node --test dist/test/stateql.test.js",
28
+ "test": "npm run build && node --test dist/test/cli.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
  "prepack": "npm test"
30
30
  },
31
31
  "keywords": [
32
32
  "database",
33
+ "mysql",
33
34
  "sqlite",
34
35
  "postgresql",
35
36
  "cli",
@@ -41,12 +42,14 @@
41
42
  "node": ">=22.5"
42
43
  },
43
44
  "dependencies": {
45
+ "mysql2": "^3.23.1",
44
46
  "node-sql-parser": "^5.4.0",
45
47
  "pg": "^8.16.3"
46
48
  },
47
49
  "devDependencies": {
48
50
  "@types/node": "^24.0.0",
49
51
  "@types/pg": "^8.15.5",
52
+ "node-pty": "^1.1.0",
50
53
  "typescript": "^7.0.0"
51
54
  }
52
55
  }