@mark1russell7/client-sqlite 0.0.0-stage → 0.1.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/CHANGELOG.md +5 -0
- package/LICENSE +21 -0
- package/README.md +747 -2
- package/dist/.tsbuildinfo +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/module.d.ts +16 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +287 -0
- package/dist/module.js.map +1 -0
- package/dist/register.d.ts +8 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +14 -0
- package/dist/register.js.map +1 -0
- package/dist/types.d.ts +91 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +20 -0
- package/dist/types.js.map +1 -0
- package/package.json +74 -3
- package/src/index.ts +88 -0
- package/src/module.ts +385 -0
- package/src/register.ts +17 -0
- package/src/types.ts +135 -0
package/README.md
CHANGED
|
@@ -1,3 +1,748 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @mark1russell7/client-sqlite
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@mark1russell7/client-sqlite)
|
|
4
|
+
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
[](https://nodejs.org/)
|
|
8
|
+
|
|
9
|
+
SQLite database operations via client procedures. Execute queries and store structured logs via `client.call()`.
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
`client-sqlite` provides SQLite database access through the client procedure ecosystem, with:
|
|
14
|
+
- **Database procedures**: Execute SQL queries and mutations
|
|
15
|
+
- **Logging procedures**: Store and query structured application logs
|
|
16
|
+
- **Migration support**: Schema versioning and migration utilities
|
|
17
|
+
- **Default log database**: Pre-configured logging at `~/logs/cli/cli.db`
|
|
18
|
+
|
|
19
|
+
The package auto-registers 4 procedures:
|
|
20
|
+
- **Database**: `db.query`, `db.execute`
|
|
21
|
+
- **Logs**: `logs.store`, `logs.query`
|
|
22
|
+
|
|
23
|
+
## Architecture
|
|
24
|
+
|
|
25
|
+
```mermaid
|
|
26
|
+
graph TB
|
|
27
|
+
subgraph "Client Ecosystem"
|
|
28
|
+
Client["@mark1russell7/client"]
|
|
29
|
+
Registry["Procedure Registry"]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
subgraph "client-sqlite Package"
|
|
33
|
+
Register["register.ts<br/>(Auto-registers procedures)"]
|
|
34
|
+
|
|
35
|
+
subgraph "Procedure Categories"
|
|
36
|
+
DB["Database Procedures<br/>db.query, db.execute"]
|
|
37
|
+
Logs["Log Procedures<br/>logs.store, logs.query"]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
Migrations["Log Table Migrations<br/>(Auto-created on first use)"]
|
|
41
|
+
Types["types.ts<br/>(Type Definitions)"]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
subgraph "docker-sqlite Layer"
|
|
45
|
+
DockerSqlite["@mark1russell7/docker-sqlite"]
|
|
46
|
+
Utilities["withConnection<br/>query, execute<br/>runMigrations"]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
subgraph "SQLite Engine"
|
|
50
|
+
SqlJs["sql.js<br/>(SQLite WASM)"]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
subgraph "Storage"
|
|
54
|
+
LogDB["~/logs/cli/cli.db<br/>(Default log database)"]
|
|
55
|
+
CustomDB["Custom databases<br/>(via dbPath parameter)"]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
Register --> Client
|
|
59
|
+
Register --> Registry
|
|
60
|
+
|
|
61
|
+
DB --> DockerSqlite
|
|
62
|
+
Logs --> DockerSqlite
|
|
63
|
+
Logs --> Migrations
|
|
64
|
+
|
|
65
|
+
DockerSqlite --> Utilities
|
|
66
|
+
Utilities --> SqlJs
|
|
67
|
+
|
|
68
|
+
SqlJs --> LogDB
|
|
69
|
+
SqlJs --> CustomDB
|
|
70
|
+
|
|
71
|
+
Types -.-> DB
|
|
72
|
+
Types -.-> Logs
|
|
73
|
+
|
|
74
|
+
style Register fill:#e1f5ff
|
|
75
|
+
style Migrations fill:#fff4e1
|
|
76
|
+
style Types fill:#f0f0f0
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Package Dependency Flow
|
|
80
|
+
|
|
81
|
+
```mermaid
|
|
82
|
+
graph LR
|
|
83
|
+
App["Your Application"]
|
|
84
|
+
ClientSqlite["@mark1russell7/client-sqlite"]
|
|
85
|
+
Client["@mark1russell7/client"]
|
|
86
|
+
DockerSqlite["@mark1russell7/docker-sqlite"]
|
|
87
|
+
SqlJs["sql.js"]
|
|
88
|
+
|
|
89
|
+
App --> ClientSqlite
|
|
90
|
+
ClientSqlite --> Client
|
|
91
|
+
ClientSqlite --> DockerSqlite
|
|
92
|
+
DockerSqlite --> SqlJs
|
|
93
|
+
|
|
94
|
+
App -.client.call.-> Client
|
|
95
|
+
Client -.executes.-> ClientSqlite
|
|
96
|
+
ClientSqlite -.queries.-> DockerSqlite
|
|
97
|
+
DockerSqlite -.uses.-> SqlJs
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Log Storage Flow
|
|
101
|
+
|
|
102
|
+
```mermaid
|
|
103
|
+
sequenceDiagram
|
|
104
|
+
participant App
|
|
105
|
+
participant LogsStore
|
|
106
|
+
participant DockerSqlite
|
|
107
|
+
participant Migration
|
|
108
|
+
participant SQLite
|
|
109
|
+
|
|
110
|
+
App->>LogsStore: logs.store({ level, message, ... })
|
|
111
|
+
LogsStore->>Migration: ensureLogsTable()
|
|
112
|
+
Migration->>DockerSqlite: withConnection()
|
|
113
|
+
DockerSqlite->>SQLite: Open ~/logs/cli/cli.db
|
|
114
|
+
Migration->>DockerSqlite: runMigrations()
|
|
115
|
+
DockerSqlite->>SQLite: CREATE TABLE IF NOT EXISTS logs
|
|
116
|
+
LogsStore->>DockerSqlite: execute(INSERT INTO logs ...)
|
|
117
|
+
DockerSqlite->>SQLite: INSERT
|
|
118
|
+
SQLite-->>DockerSqlite: lastInsertRowId
|
|
119
|
+
DockerSqlite-->>LogsStore: { id }
|
|
120
|
+
LogsStore-->>App: { id: 123 }
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Installation
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npm install @mark1russell7/client-sqlite
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Peer Dependencies
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"@mark1russell7/client": "github:mark1russell7/client#main",
|
|
134
|
+
"@mark1russell7/docker-sqlite": "github:mark1russell7/docker-sqlite#main"
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Configuration
|
|
139
|
+
|
|
140
|
+
### Default Database Path
|
|
141
|
+
|
|
142
|
+
The package uses a default database path for CLI logs:
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
// Default: ~/logs/cli/cli.db
|
|
146
|
+
const DEFAULT_DB_PATH = join(homedir(), "logs", "cli", "cli.db");
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
You can override this path in each procedure call:
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
await client.exec(
|
|
153
|
+
["db", "query"],
|
|
154
|
+
{
|
|
155
|
+
sql: "SELECT * FROM logs",
|
|
156
|
+
dbPath: "./custom/path/database.db"
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## API Reference
|
|
162
|
+
|
|
163
|
+
### Database Procedures
|
|
164
|
+
|
|
165
|
+
#### `db.query`
|
|
166
|
+
|
|
167
|
+
Execute a SQL SELECT query and return rows.
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
const result = await client.exec(
|
|
171
|
+
["db", "query"],
|
|
172
|
+
{
|
|
173
|
+
sql: "SELECT * FROM logs WHERE level = ? ORDER BY timestamp DESC",
|
|
174
|
+
params: ["error"]
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
console.log(result.rows);
|
|
179
|
+
console.log(result.columns);
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Input:**
|
|
183
|
+
```typescript
|
|
184
|
+
interface DbQueryInput {
|
|
185
|
+
sql: string; // SQL SELECT query
|
|
186
|
+
params?: unknown[]; // Query parameters (uses ? placeholders)
|
|
187
|
+
dbPath?: string; // Database path (default: ~/logs/cli/cli.db)
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**Output:**
|
|
192
|
+
```typescript
|
|
193
|
+
interface DbQueryOutput<T = Record<string, unknown>> {
|
|
194
|
+
columns: string[]; // Column names
|
|
195
|
+
rows: T[]; // Query results
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Example:**
|
|
200
|
+
```typescript
|
|
201
|
+
const result = await client.exec(
|
|
202
|
+
["db", "query"],
|
|
203
|
+
{
|
|
204
|
+
sql: `
|
|
205
|
+
SELECT level, COUNT(*) as count
|
|
206
|
+
FROM logs
|
|
207
|
+
WHERE session_id = ?
|
|
208
|
+
GROUP BY level
|
|
209
|
+
`,
|
|
210
|
+
params: ["session-123"]
|
|
211
|
+
}
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
// result.rows = [{ level: "info", count: 45 }, { level: "error", count: 2 }]
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
#### `db.execute`
|
|
218
|
+
|
|
219
|
+
Execute a SQL statement (INSERT, UPDATE, DELETE) and return the number of affected rows.
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
const result = await client.exec(
|
|
223
|
+
["db", "execute"],
|
|
224
|
+
{
|
|
225
|
+
sql: "DELETE FROM logs WHERE timestamp < ?",
|
|
226
|
+
params: ["2024-01-01"]
|
|
227
|
+
}
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
console.log(`Deleted ${result.changes} rows`);
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**Input:**
|
|
234
|
+
```typescript
|
|
235
|
+
interface DbExecuteInput {
|
|
236
|
+
sql: string; // SQL statement (INSERT, UPDATE, DELETE, etc.)
|
|
237
|
+
params?: unknown[]; // Statement parameters
|
|
238
|
+
dbPath?: string; // Database path (default: ~/logs/cli/cli.db)
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
**Output:**
|
|
243
|
+
```typescript
|
|
244
|
+
interface DbExecuteOutput {
|
|
245
|
+
changes: number; // Number of rows affected
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
**Examples:**
|
|
250
|
+
```typescript
|
|
251
|
+
// INSERT
|
|
252
|
+
await client.exec(
|
|
253
|
+
["db", "execute"],
|
|
254
|
+
{
|
|
255
|
+
sql: "INSERT INTO users (name, email) VALUES (?, ?)",
|
|
256
|
+
params: ["Alice", "alice@example.com"]
|
|
257
|
+
}
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
// UPDATE
|
|
261
|
+
await client.exec(
|
|
262
|
+
["db", "execute"],
|
|
263
|
+
{
|
|
264
|
+
sql: "UPDATE users SET active = ? WHERE id = ?",
|
|
265
|
+
params: [true, 123]
|
|
266
|
+
}
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
// DELETE
|
|
270
|
+
await client.exec(
|
|
271
|
+
["db", "execute"],
|
|
272
|
+
{
|
|
273
|
+
sql: "DELETE FROM users WHERE active = ?",
|
|
274
|
+
params: [false]
|
|
275
|
+
}
|
|
276
|
+
);
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Log Procedures
|
|
280
|
+
|
|
281
|
+
#### `logs.store`
|
|
282
|
+
|
|
283
|
+
Store a structured log entry in the database. Automatically creates the logs table on first use.
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
await client.exec(
|
|
287
|
+
["logs", "store"],
|
|
288
|
+
{
|
|
289
|
+
level: "error",
|
|
290
|
+
message: "Failed to connect to database",
|
|
291
|
+
sessionId: "session-123",
|
|
292
|
+
command: "db.connect",
|
|
293
|
+
context: "user-service",
|
|
294
|
+
data: {
|
|
295
|
+
host: "localhost",
|
|
296
|
+
port: 5432
|
|
297
|
+
},
|
|
298
|
+
errorStack: new Error().stack
|
|
299
|
+
}
|
|
300
|
+
);
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
**Input:**
|
|
304
|
+
```typescript
|
|
305
|
+
interface LogsStoreInput {
|
|
306
|
+
level: LogLevel; // Log level
|
|
307
|
+
message: string; // Log message
|
|
308
|
+
sessionId?: string; // Session ID for grouping logs
|
|
309
|
+
command?: string; // Command that generated this log
|
|
310
|
+
context?: string; // Additional context (e.g., package name)
|
|
311
|
+
data?: Record<string, unknown>; // Structured data (stored as JSON)
|
|
312
|
+
errorStack?: string; // Error stack trace
|
|
313
|
+
dbPath?: string; // Database path (default: ~/logs/cli/cli.db)
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
type LogLevel = "trace" | "debug" | "info" | "warn" | "error";
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**Output:**
|
|
320
|
+
```typescript
|
|
321
|
+
interface LogsStoreOutput {
|
|
322
|
+
id: number; // ID of the inserted log row
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**Log Table Schema:**
|
|
327
|
+
```sql
|
|
328
|
+
CREATE TABLE logs (
|
|
329
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
330
|
+
timestamp TEXT NOT NULL DEFAULT (datetime('now')),
|
|
331
|
+
level TEXT NOT NULL CHECK (level IN ('trace', 'debug', 'info', 'warn', 'error')),
|
|
332
|
+
message TEXT NOT NULL,
|
|
333
|
+
data TEXT, -- JSON string
|
|
334
|
+
session_id TEXT,
|
|
335
|
+
command TEXT,
|
|
336
|
+
context TEXT,
|
|
337
|
+
error_stack TEXT,
|
|
338
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
-- Indexes for fast queries
|
|
342
|
+
CREATE INDEX idx_logs_session ON logs(session_id);
|
|
343
|
+
CREATE INDEX idx_logs_level ON logs(level);
|
|
344
|
+
CREATE INDEX idx_logs_timestamp ON logs(timestamp);
|
|
345
|
+
CREATE INDEX idx_logs_command ON logs(command);
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
#### `logs.query`
|
|
349
|
+
|
|
350
|
+
Query log entries with filtering, pagination, and sorting.
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
const result = await client.exec(
|
|
354
|
+
["logs", "query"],
|
|
355
|
+
{
|
|
356
|
+
sessionId: "session-123",
|
|
357
|
+
level: ["error", "warn"],
|
|
358
|
+
limit: 100,
|
|
359
|
+
orderBy: "desc"
|
|
360
|
+
}
|
|
361
|
+
);
|
|
362
|
+
|
|
363
|
+
console.log(result.logs);
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
**Input:**
|
|
367
|
+
```typescript
|
|
368
|
+
interface LogsQueryInput {
|
|
369
|
+
sessionId?: string; // Filter by session ID
|
|
370
|
+
command?: string; // Filter by command
|
|
371
|
+
level?: LogLevel | LogLevel[]; // Filter by log level(s)
|
|
372
|
+
limit?: number; // Maximum number of logs to return
|
|
373
|
+
offset?: number; // Offset for pagination
|
|
374
|
+
orderBy?: "asc" | "desc"; // Order by timestamp (default: desc)
|
|
375
|
+
dbPath?: string; // Database path (default: ~/logs/cli/cli.db)
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
**Output:**
|
|
380
|
+
```typescript
|
|
381
|
+
interface LogsQueryOutput {
|
|
382
|
+
logs: LogEntry[];
|
|
383
|
+
total?: number; // Total count (if limit was applied)
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
interface LogEntry {
|
|
387
|
+
id: number;
|
|
388
|
+
timestamp: string; // ISO timestamp
|
|
389
|
+
level: LogLevel;
|
|
390
|
+
message: string;
|
|
391
|
+
data: Record<string, unknown> | null;
|
|
392
|
+
sessionId: string | null;
|
|
393
|
+
command: string | null;
|
|
394
|
+
context: string | null;
|
|
395
|
+
errorStack: string | null;
|
|
396
|
+
}
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
**Examples:**
|
|
400
|
+
```typescript
|
|
401
|
+
// Get all errors from a session
|
|
402
|
+
const { logs } = await client.exec(
|
|
403
|
+
["logs", "query"],
|
|
404
|
+
{
|
|
405
|
+
sessionId: "session-123",
|
|
406
|
+
level: "error"
|
|
407
|
+
}
|
|
408
|
+
);
|
|
409
|
+
|
|
410
|
+
// Get recent warnings and errors
|
|
411
|
+
const { logs } = await client.exec(
|
|
412
|
+
["logs", "query"],
|
|
413
|
+
{
|
|
414
|
+
level: ["warn", "error"],
|
|
415
|
+
limit: 50,
|
|
416
|
+
orderBy: "desc"
|
|
417
|
+
}
|
|
418
|
+
);
|
|
419
|
+
|
|
420
|
+
// Paginated query
|
|
421
|
+
const { logs } = await client.exec(
|
|
422
|
+
["logs", "query"],
|
|
423
|
+
{
|
|
424
|
+
command: "lib.build",
|
|
425
|
+
limit: 20,
|
|
426
|
+
offset: 40 // Page 3 (0-indexed)
|
|
427
|
+
}
|
|
428
|
+
);
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
## Usage Examples
|
|
432
|
+
|
|
433
|
+
### Basic Database Operations
|
|
434
|
+
|
|
435
|
+
```typescript
|
|
436
|
+
import { Client, LocalTransport, PROCEDURE_REGISTRY } from "@mark1russell7/client";
|
|
437
|
+
import "@mark1russell7/client-sqlite"; // registers its procedures
|
|
438
|
+
|
|
439
|
+
const client = new Client(new LocalTransport({ registry: PROCEDURE_REGISTRY }));
|
|
440
|
+
|
|
441
|
+
// Create a table
|
|
442
|
+
await client.exec(
|
|
443
|
+
["db", "execute"],
|
|
444
|
+
{
|
|
445
|
+
sql: `
|
|
446
|
+
CREATE TABLE IF NOT EXISTS users (
|
|
447
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
448
|
+
name TEXT NOT NULL,
|
|
449
|
+
email TEXT UNIQUE NOT NULL,
|
|
450
|
+
active BOOLEAN DEFAULT 1,
|
|
451
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
452
|
+
)
|
|
453
|
+
`,
|
|
454
|
+
dbPath: "./app.db"
|
|
455
|
+
}
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
// Insert data
|
|
459
|
+
await client.exec(
|
|
460
|
+
["db", "execute"],
|
|
461
|
+
{
|
|
462
|
+
sql: "INSERT INTO users (name, email) VALUES (?, ?)",
|
|
463
|
+
params: ["Alice Johnson", "alice@example.com"],
|
|
464
|
+
dbPath: "./app.db"
|
|
465
|
+
}
|
|
466
|
+
);
|
|
467
|
+
|
|
468
|
+
// Query data
|
|
469
|
+
const result = await client.exec(
|
|
470
|
+
["db", "query"],
|
|
471
|
+
{
|
|
472
|
+
sql: "SELECT * FROM users WHERE active = ? ORDER BY created_at DESC",
|
|
473
|
+
params: [1],
|
|
474
|
+
dbPath: "./app.db"
|
|
475
|
+
}
|
|
476
|
+
);
|
|
477
|
+
|
|
478
|
+
console.log(result.rows);
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### Structured Logging
|
|
482
|
+
|
|
483
|
+
```typescript
|
|
484
|
+
// Log an info message
|
|
485
|
+
await client.exec(
|
|
486
|
+
["logs", "store"],
|
|
487
|
+
{
|
|
488
|
+
level: "info",
|
|
489
|
+
message: "Starting build process",
|
|
490
|
+
sessionId: "build-2024-03-15",
|
|
491
|
+
command: "lib.build",
|
|
492
|
+
context: "@myorg/package-name"
|
|
493
|
+
}
|
|
494
|
+
);
|
|
495
|
+
|
|
496
|
+
// Log an error with stack trace
|
|
497
|
+
try {
|
|
498
|
+
// Some operation
|
|
499
|
+
throw new Error("Connection timeout");
|
|
500
|
+
} catch (error) {
|
|
501
|
+
await client.exec(
|
|
502
|
+
["logs", "store"],
|
|
503
|
+
{
|
|
504
|
+
level: "error",
|
|
505
|
+
message: error.message,
|
|
506
|
+
sessionId: "build-2024-03-15",
|
|
507
|
+
command: "lib.build",
|
|
508
|
+
context: "@myorg/package-name",
|
|
509
|
+
data: {
|
|
510
|
+
host: "api.example.com",
|
|
511
|
+
timeout: 5000
|
|
512
|
+
},
|
|
513
|
+
errorStack: error.stack
|
|
514
|
+
}
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Query logs by session
|
|
519
|
+
const { logs } = await client.exec(
|
|
520
|
+
["logs", "query"],
|
|
521
|
+
{
|
|
522
|
+
sessionId: "build-2024-03-15",
|
|
523
|
+
orderBy: "asc"
|
|
524
|
+
}
|
|
525
|
+
);
|
|
526
|
+
|
|
527
|
+
logs.forEach(log => {
|
|
528
|
+
console.log(`[${log.level}] ${log.message}`);
|
|
529
|
+
if (log.data) {
|
|
530
|
+
console.log(" Data:", log.data);
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
### Direct Database Access (Without RPC)
|
|
536
|
+
|
|
537
|
+
For lower-level access, use re-exported utilities from `docker-sqlite`:
|
|
538
|
+
|
|
539
|
+
```typescript
|
|
540
|
+
import {
|
|
541
|
+
withConnection,
|
|
542
|
+
query,
|
|
543
|
+
execute,
|
|
544
|
+
lastInsertRowId,
|
|
545
|
+
runMigrations,
|
|
546
|
+
createMigration
|
|
547
|
+
} from "@mark1russell7/client-sqlite";
|
|
548
|
+
|
|
549
|
+
// Managed connection with automatic cleanup
|
|
550
|
+
await withConnection({ dbPath: "./data/app.db" }, (db) => {
|
|
551
|
+
// Execute mutations
|
|
552
|
+
execute(db, "INSERT INTO users (name, email) VALUES (?, ?)", [
|
|
553
|
+
"Bob Smith",
|
|
554
|
+
"bob@example.com"
|
|
555
|
+
]);
|
|
556
|
+
|
|
557
|
+
const userId = lastInsertRowId(db);
|
|
558
|
+
console.log("Inserted user ID:", userId);
|
|
559
|
+
|
|
560
|
+
// Query data
|
|
561
|
+
const result = query<{ id: number; name: string; email: string }>(
|
|
562
|
+
db,
|
|
563
|
+
"SELECT * FROM users WHERE id = ?",
|
|
564
|
+
[userId]
|
|
565
|
+
);
|
|
566
|
+
|
|
567
|
+
console.log(result.rows);
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
// Connection is automatically closed after callback
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
### Database Migrations
|
|
574
|
+
|
|
575
|
+
```typescript
|
|
576
|
+
import {
|
|
577
|
+
withConnection,
|
|
578
|
+
runMigrations,
|
|
579
|
+
getMigrationStatus,
|
|
580
|
+
rollbackMigration,
|
|
581
|
+
type Migration
|
|
582
|
+
} from "@mark1russell7/client-sqlite";
|
|
583
|
+
|
|
584
|
+
const migrations: Migration[] = [
|
|
585
|
+
{
|
|
586
|
+
version: 1,
|
|
587
|
+
description: "Create users table",
|
|
588
|
+
up: `
|
|
589
|
+
CREATE TABLE users (
|
|
590
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
591
|
+
name TEXT NOT NULL,
|
|
592
|
+
email TEXT UNIQUE NOT NULL,
|
|
593
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
594
|
+
);
|
|
595
|
+
CREATE INDEX idx_users_email ON users(email);
|
|
596
|
+
`,
|
|
597
|
+
down: "DROP TABLE users;"
|
|
598
|
+
},
|
|
599
|
+
{
|
|
600
|
+
version: 2,
|
|
601
|
+
description: "Add users.active column",
|
|
602
|
+
up: "ALTER TABLE users ADD COLUMN active BOOLEAN DEFAULT 1;",
|
|
603
|
+
down: "ALTER TABLE users DROP COLUMN active;"
|
|
604
|
+
}
|
|
605
|
+
];
|
|
606
|
+
|
|
607
|
+
await withConnection({ dbPath: "./app.db" }, (db) => {
|
|
608
|
+
// Run migrations
|
|
609
|
+
runMigrations(db, migrations);
|
|
610
|
+
|
|
611
|
+
// Check migration status
|
|
612
|
+
const status = getMigrationStatus(db);
|
|
613
|
+
console.log("Current version:", status.currentVersion);
|
|
614
|
+
console.log("Applied migrations:", status.appliedMigrations);
|
|
615
|
+
|
|
616
|
+
// Rollback last migration if needed
|
|
617
|
+
// rollbackMigration(db, migrations);
|
|
618
|
+
});
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
### Type-Safe Queries
|
|
622
|
+
|
|
623
|
+
```typescript
|
|
624
|
+
// Define result types for type safety
|
|
625
|
+
interface User {
|
|
626
|
+
id: number;
|
|
627
|
+
name: string;
|
|
628
|
+
email: string;
|
|
629
|
+
active: boolean;
|
|
630
|
+
created_at: string;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
const result = await client.call<DbQueryOutput<User>>(
|
|
634
|
+
["db", "query"],
|
|
635
|
+
{
|
|
636
|
+
sql: "SELECT * FROM users WHERE active = ?",
|
|
637
|
+
params: [true],
|
|
638
|
+
dbPath: "./app.db"
|
|
639
|
+
}
|
|
640
|
+
);
|
|
641
|
+
|
|
642
|
+
// result.rows is typed as User[]
|
|
643
|
+
result.rows.forEach(user => {
|
|
644
|
+
console.log(`${user.name} <${user.email}>`);
|
|
645
|
+
});
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
## Integration with Ecosystem
|
|
649
|
+
|
|
650
|
+
### Bundle Packages
|
|
651
|
+
|
|
652
|
+
`client-sqlite` can be included in bundle packages:
|
|
653
|
+
|
|
654
|
+
```typescript
|
|
655
|
+
// In bundle-data/src/register.ts
|
|
656
|
+
import "@mark1russell7/client-sqlite"; // registers its procedures
|
|
657
|
+
import "@mark1russell7/client-mongo"; // registers its procedures
|
|
658
|
+
import "@mark1russell7/client-s3/register.js";
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
## Dependencies
|
|
662
|
+
|
|
663
|
+
### Runtime Dependencies
|
|
664
|
+
|
|
665
|
+
- **@mark1russell7/client** - Core client procedure system
|
|
666
|
+
- **@mark1russell7/docker-sqlite** - SQLite connection and query utilities
|
|
667
|
+
|
|
668
|
+
### Development Dependencies
|
|
669
|
+
|
|
670
|
+
- **@mark1russell7/cue** - Configuration and type utilities
|
|
671
|
+
- **typescript** (^5.9.3) - TypeScript compiler
|
|
672
|
+
- **@types/node** (^22.0.0) - Node.js type definitions
|
|
673
|
+
|
|
674
|
+
## Re-exported docker-sqlite Utilities
|
|
675
|
+
|
|
676
|
+
`client-sqlite` re-exports all utilities from `docker-sqlite` for direct use:
|
|
677
|
+
|
|
678
|
+
```typescript
|
|
679
|
+
// Connection management
|
|
680
|
+
export { withConnection, createConnection } from "@mark1russell7/docker-sqlite";
|
|
681
|
+
|
|
682
|
+
// Query execution
|
|
683
|
+
export { query, execute, execMultiple, lastInsertRowId } from "@mark1russell7/docker-sqlite";
|
|
684
|
+
|
|
685
|
+
// Table utilities
|
|
686
|
+
export { tableExists } from "@mark1russell7/docker-sqlite";
|
|
687
|
+
|
|
688
|
+
// Migration utilities
|
|
689
|
+
export {
|
|
690
|
+
getMigrationStatus,
|
|
691
|
+
runMigrations,
|
|
692
|
+
rollbackMigration,
|
|
693
|
+
createMigration
|
|
694
|
+
} from "@mark1russell7/docker-sqlite";
|
|
695
|
+
|
|
696
|
+
// Types
|
|
697
|
+
export type {
|
|
698
|
+
ConnectionConfig,
|
|
699
|
+
ConnectionCallback,
|
|
700
|
+
QueryResult,
|
|
701
|
+
ExecuteResult,
|
|
702
|
+
Migration,
|
|
703
|
+
MigrationStatus,
|
|
704
|
+
Database
|
|
705
|
+
} from "@mark1russell7/docker-sqlite";
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
## Package Structure
|
|
709
|
+
|
|
710
|
+
```
|
|
711
|
+
client-sqlite/
|
|
712
|
+
├── src/
|
|
713
|
+
│ ├── types.ts # Type definitions
|
|
714
|
+
│ ├── register.ts # Auto-registration + procedure implementations
|
|
715
|
+
│ └── index.ts # Main entry point
|
|
716
|
+
├── dist/ # Compiled output
|
|
717
|
+
├── package.json
|
|
718
|
+
├── tsconfig.json
|
|
719
|
+
└── README.md
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
## Development
|
|
723
|
+
|
|
724
|
+
### Build
|
|
725
|
+
|
|
726
|
+
```bash
|
|
727
|
+
npm run build
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
### Type Check
|
|
731
|
+
|
|
732
|
+
```bash
|
|
733
|
+
npm run typecheck
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
### Clean
|
|
737
|
+
|
|
738
|
+
```bash
|
|
739
|
+
npm run clean
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
## License
|
|
743
|
+
|
|
744
|
+
MIT
|
|
745
|
+
|
|
746
|
+
## Author
|
|
747
|
+
|
|
748
|
+
Mark Russell <marktheprogrammer17@gmail.com>
|