@pilaniaanand/driver-interface 0.5.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.
@@ -0,0 +1,273 @@
1
+ /**
2
+ * @pilaniaanand/driver-interface
3
+ *
4
+ * This is the single contract every database adapter implements. The registry
5
+ * (apps/server) only ever talks to this interface — it never imports a
6
+ * concrete driver directly. Adding support for a new database means writing
7
+ * one new package that implements `DatabaseDriver` and registering it; no
8
+ * other part of the system changes.
9
+ *
10
+ * Design rules baked into this contract (see architecture plan):
11
+ * - Nothing here returns a full result set. Reads are either paginated
12
+ * (`queryRows`) or streamed (`streamQuery`), so a caller can never
13
+ * accidentally materialize a trillion-row table in memory.
14
+ * - Row counts are explicitly split into a fast estimate and a slow exact
15
+ * count, so the UI can show something instantly and let the user opt in
16
+ * to the expensive version.
17
+ * - Everything long-running is cancellable via an AbortSignal.
18
+ */
19
+ export type QueryLanguage = "sql" | "mongo" | "redis-command";
20
+ export type ColumnType = "string" | "number" | "boolean" | "date" | "datetime" | "json" | "binary" | "null" | "unknown";
21
+ export interface ColumnDefinition {
22
+ name: string;
23
+ type: ColumnType;
24
+ nativeType: string;
25
+ nullable: boolean;
26
+ isPrimaryKey: boolean;
27
+ isForeignKey: boolean;
28
+ references?: {
29
+ table: string;
30
+ column: string;
31
+ };
32
+ defaultValue?: string | null;
33
+ }
34
+ export interface TableDefinition {
35
+ schema?: string;
36
+ name: string;
37
+ kind: "table" | "view" | "collection" | "materialized_view";
38
+ columns: ColumnDefinition[];
39
+ estimatedRowCount?: number;
40
+ }
41
+ export interface SchemaSummary {
42
+ name: string;
43
+ tables: Array<Pick<TableDefinition, "schema" | "name" | "kind">>;
44
+ }
45
+ /** TLS options for connecting directly to a database that requires (or accepts) certificate-based auth. */
46
+ export interface SslConfig {
47
+ enabled: boolean;
48
+ rejectUnauthorized?: boolean;
49
+ ca?: string;
50
+ cert?: string;
51
+ key?: string;
52
+ }
53
+ /**
54
+ * Connects to `host`/`port` through an SSH server first — the standard way
55
+ * to reach a database sitting in a private subnet behind a bastion/jump
56
+ * host (e.g. AWS RDS). `privateKey` accepts OpenSSH PEM or PuTTY PPK
57
+ * contents; ssh2 auto-detects the format.
58
+ */
59
+ export interface SshTunnelConfig {
60
+ enabled: boolean;
61
+ host: string;
62
+ port?: number;
63
+ username: string;
64
+ privateKey?: string;
65
+ passphrase?: string;
66
+ password?: string;
67
+ }
68
+ export interface ConnectionConfig {
69
+ id: string;
70
+ driver: string;
71
+ host?: string;
72
+ port?: number;
73
+ database?: string;
74
+ username?: string;
75
+ password?: string;
76
+ filePath?: string;
77
+ ssl?: boolean | SslConfig;
78
+ sshTunnel?: SshTunnelConfig;
79
+ /**
80
+ * App-level safety net: when true, every write/DDL operation against this
81
+ * connection is rejected before it reaches the driver — insertRow/
82
+ * updateCell/deleteRow outright, and execute() for any query whose intent
83
+ * isn't a plain read (see isDestructiveExec). This is enforced by the
84
+ * server (routes/connections.ts), not by individual drivers.
85
+ *
86
+ * This is a UX/compliance safety net, not a substitute for real access
87
+ * control — a connection string with write privileges can still write if
88
+ * something reaches the underlying client directly. For a guarantee that
89
+ * survives an application bug, connect with a database role that only
90
+ * has SELECT granted (or point this at a read replica) — that's the one
91
+ * layer this app cannot bypass no matter what.
92
+ */
93
+ readOnly?: boolean;
94
+ extra?: Record<string, unknown>;
95
+ }
96
+ /** Normalizes the two `ssl` shapes drivers can receive into one, or undefined if TLS isn't requested. */
97
+ export declare function resolveSsl(ssl: ConnectionConfig["ssl"]): SslConfig | undefined;
98
+ export declare function assertSafeIdentifier(name: string, kind: string): void;
99
+ export interface CursorPage {
100
+ /** Opaque, driver-defined cursor. Callers must not parse this string. */
101
+ cursor: string | null;
102
+ }
103
+ export interface QueryRowsOptions {
104
+ table: string;
105
+ schema?: string;
106
+ columns?: string[];
107
+ filters?: QueryFilter[];
108
+ sort?: {
109
+ column: string;
110
+ direction: "asc" | "desc";
111
+ }[];
112
+ pageSize: number;
113
+ afterCursor?: string | null;
114
+ signal?: AbortSignal;
115
+ }
116
+ export interface QueryFilter {
117
+ column: string;
118
+ op: "=" | "!=" | ">" | ">=" | "<" | "<=" | "like" | "in" | "is_null" | "is_not_null";
119
+ value?: unknown;
120
+ }
121
+ /** Emitted by drivers that support native change notification (see DriverConnection.watchTable). */
122
+ export interface RowChangeEvent {
123
+ type: "insert" | "update" | "delete";
124
+ row?: Record<string, unknown>;
125
+ primaryKey?: Record<string, unknown>;
126
+ column?: string;
127
+ value?: unknown;
128
+ }
129
+ /**
130
+ * Shared building block for drivers with no native change feed: given two
131
+ * full-table snapshots and the table's primary key columns, produces the
132
+ * same RowChangeEvent shape a native watcher would emit. A changed row is
133
+ * reported as a single "__row__" update (see useTableRows.ts) rather than
134
+ * diffed field-by-field — the snapshot doesn't tell us which columns moved,
135
+ * only that the row did.
136
+ */
137
+ export declare function diffTableSnapshots(prevRows: Record<string, unknown>[], currRows: Record<string, unknown>[], pkColumns: string[]): RowChangeEvent[];
138
+ export interface QueryRowsResult {
139
+ rows: Record<string, unknown>[];
140
+ nextCursor: string | null;
141
+ columns: ColumnDefinition[];
142
+ }
143
+ export interface RowCountEstimate {
144
+ value: number;
145
+ exact: false;
146
+ source: "statistics" | "unsupported";
147
+ }
148
+ export interface RowCountExact {
149
+ value: number;
150
+ exact: true;
151
+ }
152
+ /**
153
+ * A read query in whatever shape the target driver's queryLanguage expects,
154
+ * used by streamQuery(). Discriminated on `language` so each driver's
155
+ * implementation only has to handle the one variant matching its own
156
+ * `capabilities.queryLanguage` — TypeScript rejects the others at compile
157
+ * time, and callers (the query editor UI, the stream route) never need to
158
+ * guess or JSON.parse a string to figure out what they're holding.
159
+ */
160
+ export type RedisKeyType = "string" | "hash" | "list" | "set" | "zset" | "stream";
161
+ export type QuerySpec = {
162
+ language: "sql";
163
+ sql: string;
164
+ params?: unknown[];
165
+ } | {
166
+ language: "mongo";
167
+ collection: string;
168
+ /** Either a find() (filter/sort/limit) or an aggregate() (pipeline) — not both. */
169
+ filter?: Record<string, unknown>;
170
+ sort?: Record<string, 1 | -1>;
171
+ limit?: number;
172
+ pipeline?: Record<string, unknown>[];
173
+ } | {
174
+ language: "redis-command";
175
+ /** Browse keys of one type (SCAN under the hood) — see DriverConnection.queryRows for the "table" equivalent. */
176
+ type: RedisKeyType;
177
+ pattern?: string;
178
+ limit?: number;
179
+ };
180
+ /**
181
+ * A write/DDL query for execute(). Separate from QuerySpec because a
182
+ * driver's write shape can genuinely differ from its read shape (e.g.
183
+ * MongoDB reads via filter/sort/pipeline but writes via an explicit
184
+ * op + filter/update/doc) — forcing them into one type would leave unused
185
+ * fields on one side or the other.
186
+ */
187
+ export type ExecSpec = {
188
+ language: "sql";
189
+ sql: string;
190
+ params?: unknown[];
191
+ } | {
192
+ language: "mongo";
193
+ op: "insertOne" | "updateOne" | "deleteOne" | "deleteMany";
194
+ collection: string;
195
+ filter?: Record<string, unknown>;
196
+ update?: Record<string, unknown>;
197
+ doc?: Record<string, unknown>;
198
+ } | {
199
+ language: "redis-command";
200
+ /** Raw write command + args, e.g. ["SET", "foo", "bar"] or ["DEL", "foo"]. */
201
+ command: string[];
202
+ };
203
+ export interface StreamQueryOptions {
204
+ query: QuerySpec;
205
+ chunkSize?: number;
206
+ signal?: AbortSignal;
207
+ }
208
+ /**
209
+ * True if this write/DDL/execute request should be blocked when the
210
+ * connection is read-only. Deliberately fails closed: for SQL, anything not
211
+ * lexically recognizable as a plain read is treated as destructive; for
212
+ * Mongo, execute() only ever carries write ops (reads go through
213
+ * queryRows), so it's always destructive; for Redis, only a fixed allowlist
214
+ * of read commands is permitted.
215
+ */
216
+ export declare function isDestructiveExec(query: ExecSpec): boolean;
217
+ export interface QueryExecResult {
218
+ columns: ColumnDefinition[];
219
+ affectedRows?: number;
220
+ durationMs: number;
221
+ }
222
+ /**
223
+ * The contract. All methods are async / async-iterable so a driver can wrap
224
+ * a network call, a local file read, or an in-process embedded engine
225
+ * identically from the registry's point of view.
226
+ */
227
+ export interface DatabaseDriver {
228
+ readonly key: string;
229
+ readonly displayName: string;
230
+ readonly capabilities: {
231
+ transactions: boolean;
232
+ schemas: boolean;
233
+ streaming: boolean;
234
+ cancellation: boolean;
235
+ queryLanguage: QueryLanguage;
236
+ };
237
+ testConnection(config: ConnectionConfig): Promise<{
238
+ ok: boolean;
239
+ message?: string;
240
+ }>;
241
+ connect(config: ConnectionConfig): Promise<DriverConnection>;
242
+ }
243
+ export interface DriverConnection {
244
+ readonly id: string;
245
+ listSchemas(): Promise<SchemaSummary[]>;
246
+ listTables(schema?: string): Promise<TableDefinition[]>;
247
+ describeTable(table: string, schema?: string): Promise<TableDefinition>;
248
+ /** Keyset-paginated row browsing for the data grid. Never uses OFFSET. */
249
+ queryRows(options: QueryRowsOptions): Promise<QueryRowsResult>;
250
+ /** Inserts a new record. Returns the inserted row as the driver sees it (with any DB-generated defaults filled in). */
251
+ insertRow(table: string, schema: string | undefined, values: Record<string, unknown>): Promise<Record<string, unknown>>;
252
+ /** Deletes the record(s) matching every column in primaryKey. */
253
+ deleteRow(table: string, schema: string | undefined, primaryKey: Record<string, unknown>): Promise<void>;
254
+ /**
255
+ * Optional: subscribe to native change notifications for a table (e.g.
256
+ * MongoDB Change Streams). Only implemented by drivers whose database
257
+ * supports this without extra setup (triggers, replication config,
258
+ * etc). Returns an unsubscribe function. Callers must call it exactly
259
+ * once when no longer interested — drivers that implement this should
260
+ * treat it as a reference-counted resource internally if needed.
261
+ */
262
+ watchTable?(table: string, schema: string | undefined, onChange: (event: RowChangeEvent) => void): () => void;
263
+ /** Fast, approximate — reads DB statistics, not a full scan. */
264
+ estimateRowCount(table: string, schema?: string): Promise<RowCountEstimate>;
265
+ /** Slow, exact — an opt-in COUNT(*) style scan. Must respect signal. */
266
+ countRowsExact(table: string, schema?: string, signal?: AbortSignal): Promise<RowCountExact>;
267
+ /** Arbitrary SQL/query execution for the query editor, streamed in chunks. */
268
+ streamQuery(options: StreamQueryOptions): AsyncIterableIterator<QueryRowsResult>;
269
+ /** Non-SELECT execution (INSERT/UPDATE/DELETE/DDL, a mongo write command, or a redis write command), also cancellable. */
270
+ execute(query: ExecSpec, signal?: AbortSignal): Promise<QueryExecResult>;
271
+ updateCell(table: string, schema: string | undefined, primaryKey: Record<string, unknown>, column: string, value: unknown): Promise<void>;
272
+ close(): Promise<void>;
273
+ }
package/dist/index.js ADDED
@@ -0,0 +1,118 @@
1
+ /**
2
+ * @pilaniaanand/driver-interface
3
+ *
4
+ * This is the single contract every database adapter implements. The registry
5
+ * (apps/server) only ever talks to this interface — it never imports a
6
+ * concrete driver directly. Adding support for a new database means writing
7
+ * one new package that implements `DatabaseDriver` and registering it; no
8
+ * other part of the system changes.
9
+ *
10
+ * Design rules baked into this contract (see architecture plan):
11
+ * - Nothing here returns a full result set. Reads are either paginated
12
+ * (`queryRows`) or streamed (`streamQuery`), so a caller can never
13
+ * accidentally materialize a trillion-row table in memory.
14
+ * - Row counts are explicitly split into a fast estimate and a slow exact
15
+ * count, so the UI can show something instantly and let the user opt in
16
+ * to the expensive version.
17
+ * - Everything long-running is cancellable via an AbortSignal.
18
+ */
19
+ /** Normalizes the two `ssl` shapes drivers can receive into one, or undefined if TLS isn't requested. */
20
+ export function resolveSsl(ssl) {
21
+ if (!ssl)
22
+ return undefined;
23
+ if (ssl === true)
24
+ return { enabled: true };
25
+ return ssl.enabled ? ssl : undefined;
26
+ }
27
+ /**
28
+ * Matches a bare SQL identifier: letters/digits/underscore, not starting
29
+ * with a digit. SQL has no parameterized-identifier mechanism the way it
30
+ * does for values (no driver supports `WHERE $1 = $2` binding a column
31
+ * name) — every SQL driver's structured operations (queryRows filters,
32
+ * insertRow/updateCell/deleteRow column names, the table/schema name
33
+ * itself) must run every client-supplied identifier through
34
+ * `assertSafeIdentifier` before interpolating it into a query string.
35
+ * Rejecting anything outside this charset closes identifier-based SQL
36
+ * injection outright — no quote, backtick, semicolon, or comment sequence
37
+ * can ever reach the query text.
38
+ */
39
+ const SAFE_SQL_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
40
+ export function assertSafeIdentifier(name, kind) {
41
+ if (typeof name !== "string" || !SAFE_SQL_IDENTIFIER.test(name)) {
42
+ throw new Error(`Invalid ${kind} name: ${JSON.stringify(name)}`);
43
+ }
44
+ }
45
+ /**
46
+ * Shared building block for drivers with no native change feed: given two
47
+ * full-table snapshots and the table's primary key columns, produces the
48
+ * same RowChangeEvent shape a native watcher would emit. A changed row is
49
+ * reported as a single "__row__" update (see useTableRows.ts) rather than
50
+ * diffed field-by-field — the snapshot doesn't tell us which columns moved,
51
+ * only that the row did.
52
+ */
53
+ export function diffTableSnapshots(prevRows, currRows, pkColumns) {
54
+ const keyOf = (row) => JSON.stringify(pkColumns.map((c) => row[c]));
55
+ const pkOf = (row) => Object.fromEntries(pkColumns.map((c) => [c, row[c]]));
56
+ const prevByKey = new Map(prevRows.map((r) => [keyOf(r), r]));
57
+ const currByKey = new Map(currRows.map((r) => [keyOf(r), r]));
58
+ const events = [];
59
+ for (const [key, row] of currByKey) {
60
+ const prevRow = prevByKey.get(key);
61
+ if (!prevRow)
62
+ events.push({ type: "insert", row });
63
+ else if (JSON.stringify(prevRow) !== JSON.stringify(row)) {
64
+ events.push({ type: "update", primaryKey: pkOf(row), column: "__row__", value: row });
65
+ }
66
+ }
67
+ for (const [key, row] of prevByKey) {
68
+ if (!currByKey.has(key))
69
+ events.push({ type: "delete", primaryKey: pkOf(row) });
70
+ }
71
+ return events;
72
+ }
73
+ const SQL_SAFE_LEADING_KEYWORDS = new Set(["select", "with", "explain", "show", "describe", "desc", "pragma", "values"]);
74
+ // Whole-word scan for write/DDL verbs anywhere in the statement — catches a
75
+ // write smuggled inside a CTE (`WITH x AS (DELETE FROM t RETURNING *) SELECT * FROM x`),
76
+ // which a leading-keyword check alone would miss.
77
+ const SQL_WRITE_VERB = /\b(insert|update|delete|drop|alter|truncate|create|grant|revoke|merge|call|copy|vacuum|reindex|lock|replace|into\s+outfile)\b/i;
78
+ const REDIS_SAFE_READ_COMMANDS = new Set([
79
+ "get", "mget", "strlen", "getrange", "exists", "type", "ttl", "pttl", "scan", "keys", "dbsize",
80
+ "hget", "hmget", "hgetall", "hkeys", "hvals", "hlen", "hrandfield", "hexists", "hscan", "hstrlen",
81
+ "lrange", "llen", "lindex", "lpos",
82
+ "smembers", "scard", "sismember", "smismember", "srandmember", "sscan", "sinter", "sunion", "sdiff",
83
+ "zrange", "zrangebyscore", "zrevrange", "zrevrangebyscore", "zscore", "zmscore", "zcard", "zcount",
84
+ "zrank", "zrevrank", "zscan",
85
+ "xrange", "xrevrange", "xlen", "xread",
86
+ "ping", "echo", "info", "time", "config", "client", "object", "memory", "randomkey", "touch",
87
+ ]);
88
+ /**
89
+ * True if this write/DDL/execute request should be blocked when the
90
+ * connection is read-only. Deliberately fails closed: for SQL, anything not
91
+ * lexically recognizable as a plain read is treated as destructive; for
92
+ * Mongo, execute() only ever carries write ops (reads go through
93
+ * queryRows), so it's always destructive; for Redis, only a fixed allowlist
94
+ * of read commands is permitted.
95
+ */
96
+ export function isDestructiveExec(query) {
97
+ if (query.language === "mongo")
98
+ return true;
99
+ if (query.language === "redis-command") {
100
+ const cmd = query.command[0]?.toLowerCase();
101
+ return !cmd || !REDIS_SAFE_READ_COMMANDS.has(cmd);
102
+ }
103
+ // SQL
104
+ const statements = query.sql
105
+ .replace(/--[^\n]*/g, " ") // line comments
106
+ .replace(/\/\*[\s\S]*?\*\//g, " ") // block comments
107
+ .split(";")
108
+ .map((s) => s.trim())
109
+ .filter(Boolean);
110
+ if (statements.length !== 1)
111
+ return true; // no legitimate read needs multiple statements
112
+ const stmt = statements[0];
113
+ const leading = stmt.match(/^[A-Za-z]+/)?.[0]?.toLowerCase();
114
+ if (!leading || !SQL_SAFE_LEADING_KEYWORDS.has(leading))
115
+ return true;
116
+ return SQL_WRITE_VERB.test(stmt);
117
+ }
118
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "@pilaniaanand/driver-interface",
3
+ "version": "0.5.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "devDependencies": {
8
+ "@types/node": "^26.4.1",
9
+ "typescript": "^7.0.2"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "scripts": {
18
+ "typecheck": "tsc --noEmit",
19
+ "build": "tsc -p tsconfig.json"
20
+ }
21
+ }