@crvouga/mockingbird-service-sqlite 1.2.0 → 1.3.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 CHANGED
@@ -1,6 +1,22 @@
1
1
  # Changelog — @crvouga/mockingbird-service-sqlite
2
2
 
3
- ## 1.2.0 (2026-09-30)
3
+ ## 1.3.0 (2026-10-01)
4
+
5
+ ### Features
6
+
7
+ - record SQL timelines and serve the admin explorer ([8ced17a](https://github.com/crvouga/mockingbird/commit/8ced17ac398e386ef4e9d7e01fc7744c34b95d07))
8
+
9
+ ### Fixes and improvements
10
+
11
+ - typecheck SQL admin timelines without a built sqlite port ([072daf4](https://github.com/crvouga/mockingbird/commit/072daf439f3967823149d7b0a8a9ce664d25097c))
12
+
13
+ ## 1.2.1 (2026-09-29)
14
+
15
+ ### Fixes and improvements
16
+
17
+ - keep hosted pages inside narrow hosts and popups ([6512323](https://github.com/crvouga/mockingbird/commit/6512323198cb00b99005f3d2cfa5b9f1e6e321a7))
18
+
19
+ ## 1.2.0 (2026-09-29)
4
20
 
5
21
  ### Features
6
22
 
package/README.md CHANGED
@@ -145,16 +145,39 @@ The mocks create their own tables (`mockingbird_records`, `mockingbird_sequences
145
145
  resetting one mock leaves the others' data in a shared database intact. Any other client with the same sync surface (better-sqlite3, a
146
146
  wrapped `bun:sqlite`) also satisfies the port.
147
147
 
148
+ ### Socket
149
+
150
+ SQLite has no client/server protocol, so the stock `sqlite3` CLI cannot attach to this
151
+ engine. `@crvouga/mockingbird-service-sqlite/socket` is a Node entry (it needs `node:net`)
152
+ that listens on `sqlite://host:port/name` and speaks a length-prefixed JSON frame. The
153
+ in-package `connect(uri)` client runs statements against it. Portable queries, including
154
+ from a browser, go through the admin API (`POST /__admin/sql/query`) instead.
155
+
156
+ ```ts
157
+ import { connect, serve } from "@crvouga/mockingbird-service-sqlite/socket"
158
+
159
+ const server = await serve("sqlite://127.0.0.1:0/app")
160
+ const db = await connect(server.url)
161
+ await db.exec("CREATE TABLE notes (body TEXT)")
162
+ await db.close()
163
+ await server.close()
164
+ ```
165
+
166
+ `mockingbird-sqlite serve` prints that URI. `createAdmin` from
167
+ `@crvouga/mockingbird-service-sqlite/admin` serves the same `/__admin` surface as every
168
+ other mock, including the table explorer.
169
+
148
170
  ### Method semantics
149
171
 
150
172
  | Method | Behaviour |
151
173
  | --- | --- |
152
174
  | `exec(sql)` | Runs all semicolon-separated statements; **discards** row results (`void`). Does **not** accept bind parameters. Read `db.changes` / `db.lastInsertRowid` afterwards if needed (counters reflect the **most recent** completed statement, matching SQLite). |
153
- | `query(sql, params?, { at? }?)` | **Single statement only** (trailing `;` is fine). Returns all rows. `at` queries an immutable checkpoint without changing live state. Multi-statement scripts throw `misuse`. |
175
+ | `query(sql, params?, { at? }?)` | **Single statement only** (trailing `;` is fine). Returns all rows. `at` is a `Snapshot` or a timeline checkpoint id and queries that checkpoint without changing live state. Multi-statement scripts throw `misuse`. |
154
176
  | `prepare(sql)` | **Single statement only**. Parses immediately; the AST is reused. Pass binds as rest args to `run` / `all` / `get` / `result` on each call. |
155
177
  | `transaction(fn)` | If idle: `BEGIN`, `fn()`, `COMMIT`, or `ROLLBACK` + rethrow. If already in a transaction: nested savepoint. A nested SQL `BEGIN` still errors. `close()` inside `fn` throws `misuse`. |
156
- | `snapshot()` | Freeze a reusable `Snapshot` template (no encode). Illegal inside a transaction. |
157
- | `checkpoint()` / `branch(at?)` | Name a COW snapshot as a checkpoint; open an isolated branch from it (or current state). |
178
+ | `snapshot()` | Freeze a reusable `Snapshot` template (no encode) and commit it on the followed timeline branch. Illegal inside a transaction. |
179
+ | `checkpoint()` / `branch(at?)` | `checkpoint` records the same timeline point as `snapshot`. `branch` opens an isolated database from a snapshot (or the current state). |
180
+ | `record(branch?)` / `fork(name, at?)` / `checkout(id, branch?)` / `reset()` | Timeline history on this database. `record` commits the live state. `fork` adds a branch pointer and does not switch live state. `checkout` installs a checkpoint. `reset` returns to the origin checkpoint on `main`. `history` lists heads and checkpoints. |
158
181
  | `Snapshot.open()` | Copy-on-write fork from a template. The parent stays open. |
159
182
  | `Snapshot.encode()` | Lazy SQLM blob for persistence / worker boot (computed once, cached). |
160
183
  | `Snapshot.decode(bytes)` | Decode a blob once per `Uint8Array` (WeakMap); later `open()` calls are copy-on-write. |
@@ -295,24 +318,44 @@ Stable runtime exports of the main entry:
295
318
  | `Statement` | Class returned by `db.prepare(sql)` (not constructed directly): `run`, `all`, `get`, `result`. |
296
319
  | `SqliteError` | Error class thrown for SQL and API errors: `category` (`ErrorCategory`), `sqliteCode` / `code` (SQLite result-code name, e.g. `"SQLITE_CONSTRAINT_UNIQUE"`; default `"SQLITE_ERROR"`). |
297
320
 
298
- Signatures (types are exported too: `DatabaseOptions`, `RunResult`, `ResultSet`, `ErrorCategory`,
299
- `BindValue`, `QueryRow`, `QueryValue`):
321
+ Signatures (types are exported too: `DatabaseOptions`, `HistoryCheckpoint`, `DatabaseHistory`,
322
+ `RunResult`, `ResultSet`, `ErrorCategory`, `BindValue`, `QueryRow`, `QueryValue`):
300
323
 
301
324
  ```ts
302
325
  interface DatabaseOptions {
303
326
  seed?: number | bigint // default 1; ignored when random is "os"
304
327
  random?: "deterministic" | "os" // default "deterministic"; "os" is CSPRNG like SQLite
305
328
  now?: Date | (() => Date) | "system" // default 2000-01-01T00:00:00.000Z; "system" is wall clock
329
+ maxCheckpoints?: number // timeline checkpoints to retain; default 1000
330
+ }
331
+
332
+ interface HistoryCheckpoint {
333
+ id: string
334
+ branch: string
335
+ parent: string | null
336
+ at: number
337
+ }
338
+
339
+ interface DatabaseHistory {
340
+ readonly size: number
341
+ head(branch?: string): HistoryCheckpoint | undefined
342
+ branches(): Readonly<Record<string, string>>
343
+ checkpoints(): readonly HistoryCheckpoint[]
306
344
  }
307
345
 
308
346
  declare class Database {
309
347
  constructor(options?: DatabaseOptions)
310
348
  exec(sql: string): void
311
- query<T = QueryRow>(sql: string, params?: readonly BindValue[], options?: { at?: Snapshot }): T[]
349
+ query<T = QueryRow>(sql: string, params?: readonly BindValue[], options?: { at?: Snapshot | string }): T[]
312
350
  prepare(sql: string): Statement
313
351
  transaction<T>(fn: () => T): T
314
352
  snapshot(): Snapshot
315
353
  checkpoint(): Snapshot
354
+ record(branch?: string): HistoryCheckpoint
355
+ fork(name: string, at?: string): HistoryCheckpoint
356
+ checkout(id: string, branch?: string): HistoryCheckpoint
357
+ reset(): HistoryCheckpoint
358
+ readonly history: DatabaseHistory
316
359
  branch(at?: Snapshot): Database
317
360
  close(): void // also [Symbol.dispose] when available
318
361
  readonly changes: number
@@ -0,0 +1,13 @@
1
+ import type { Database, DatabaseOptions } from "./api/database.js";
2
+
3
+ export interface AdminOptions {
4
+ database?: Database;
5
+ adminKey?: string;
6
+ databaseOptions?: DatabaseOptions;
7
+ }
8
+
9
+ export interface AdminServer {
10
+ fetch(request: Request): Promise<Response>;
11
+ }
12
+
13
+ export declare function createAdmin(options?: AdminOptions): AdminServer;